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"
22 #ifdef HAVE_SYS_TIME_H
34 #ifdef USE_LINUX_PACKET
35 #include <sys/ioctl.h>
41 /**********************************************************************
42 *%FUNCTION: parseForHostUniq
47 * extra -- user-supplied pointer. This is assumed to be a pointer to int.
51 * If a HostUnique tag is found which matches our PID, sets *extra to 1.
52 ***********************************************************************/
54 parseForHostUniq(UINT16_t type, UINT16_t len, unsigned char *data,
57 int *val = (int *) extra;
58 if (type == TAG_HOST_UNIQ && len == sizeof(pid_t)) {
60 memcpy(&tmp, data, len);
61 if (tmp == getpid()) {
67 /**********************************************************************
68 *%FUNCTION: packetIsForMe
70 * conn -- PPPoE connection info
71 * packet -- a received PPPoE packet
73 * 1 if packet is for this PPPoE daemon; 0 otherwise.
75 * If we are using the Host-Unique tag, verifies that packet contains
76 * our unique identifier.
77 ***********************************************************************/
79 packetIsForMe(PPPoEConnection *conn, PPPoEPacket *packet)
83 /* If packet is not directed to our MAC address, forget it */
84 if (memcmp(packet->ethHdr.h_dest, conn->myEth, ETH_ALEN)) return 0;
86 /* If we're not using the Host-Unique tag, then accept the packet */
87 if (!conn->useHostUniq) return 1;
89 parsePacket(packet, parseForHostUniq, &forMe);
93 /**********************************************************************
94 *%FUNCTION: parsePADOTags
99 * extra -- extra user data. Should point to a PacketCriteria structure
100 * which gets filled in according to selected AC name and service
105 * Picks interesting tags out of a PADO packet
106 ***********************************************************************/
108 parsePADOTags(UINT16_t type, UINT16_t len, unsigned char *data,
111 struct PacketCriteria *pc = (struct PacketCriteria *) extra;
112 PPPoEConnection *conn = pc->conn;
118 if (conn->printACNames) {
119 info("Access-Concentrator: %.*s", (int) len, data);
121 if (conn->acName && len == strlen(conn->acName) &&
122 !strncmp((char *) data, conn->acName, len)) {
126 case TAG_SERVICE_NAME:
127 pc->seenServiceName = 1;
128 if (conn->serviceName && len == strlen(conn->serviceName) &&
129 !strncmp((char *) data, conn->serviceName, len)) {
130 pc->serviceNameOK = 1;
134 conn->cookie.type = htons(type);
135 conn->cookie.length = htons(len);
136 memcpy(conn->cookie.payload, data, len);
138 case TAG_RELAY_SESSION_ID:
139 conn->relayId.type = htons(type);
140 conn->relayId.length = htons(len);
141 memcpy(conn->relayId.payload, data, len);
143 case TAG_SERVICE_NAME_ERROR:
144 error("PADO: Service-Name-Error: %.*s", (int) len, data);
147 case TAG_AC_SYSTEM_ERROR:
148 error("PADO: System-Error: %.*s", (int) len, data);
151 case TAG_GENERIC_ERROR:
152 error("PADO: Generic-Error: %.*s", (int) len, data);
158 /**********************************************************************
159 *%FUNCTION: parsePADSTags
164 * extra -- extra user data (pointer to PPPoEConnection structure)
168 * Picks interesting tags out of a PADS packet
169 ***********************************************************************/
171 parsePADSTags(UINT16_t type, UINT16_t len, unsigned char *data,
174 PPPoEConnection *conn = (PPPoEConnection *) extra;
176 case TAG_SERVICE_NAME:
177 dbglog("PADS: Service-Name: '%.*s'", (int) len, data);
179 case TAG_SERVICE_NAME_ERROR:
180 error("PADS: Service-Name-Error: %.*s", (int) len, data);
183 case TAG_AC_SYSTEM_ERROR:
184 error("PADS: System-Error: %.*s", (int) len, data);
187 case TAG_GENERIC_ERROR:
188 error("PADS: Generic-Error: %.*s", (int) len, data);
191 case TAG_RELAY_SESSION_ID:
192 conn->relayId.type = htons(type);
193 conn->relayId.length = htons(len);
194 memcpy(conn->relayId.payload, data, len);
199 /***********************************************************************
202 * conn -- PPPoEConnection structure
206 * Sends a PADI packet
207 ***********************************************************************/
209 sendPADI(PPPoEConnection *conn)
212 unsigned char *cursor = packet.payload;
213 PPPoETag *svc = (PPPoETag *) (&packet.payload);
214 UINT16_t namelen = 0;
216 int omit_service_name = 0;
218 if (conn->serviceName) {
219 namelen = (UINT16_t) strlen(conn->serviceName);
220 if (!strcmp(conn->serviceName, "NO-SERVICE-NAME-NON-RFC-COMPLIANT")) {
221 omit_service_name = 1;
225 /* Set destination to Ethernet broadcast address */
226 memset(packet.ethHdr.h_dest, 0xFF, ETH_ALEN);
227 memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
229 packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
230 packet.vertype = PPPOE_VER_TYPE(1, 1);
231 packet.code = CODE_PADI;
234 if (!omit_service_name) {
235 plen = TAG_HDR_SIZE + namelen;
236 CHECK_ROOM(cursor, packet.payload, plen);
238 svc->type = TAG_SERVICE_NAME;
239 svc->length = htons(namelen);
241 if (conn->serviceName) {
242 memcpy(svc->payload, conn->serviceName, strlen(conn->serviceName));
244 cursor += namelen + TAG_HDR_SIZE;
249 /* If we're using Host-Uniq, copy it over */
250 if (conn->useHostUniq) {
252 pid_t pid = getpid();
253 hostUniq.type = htons(TAG_HOST_UNIQ);
254 hostUniq.length = htons(sizeof(pid));
255 memcpy(hostUniq.payload, &pid, sizeof(pid));
256 CHECK_ROOM(cursor, packet.payload, sizeof(pid) + TAG_HDR_SIZE);
257 memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
258 cursor += sizeof(pid) + TAG_HDR_SIZE;
259 plen += sizeof(pid) + TAG_HDR_SIZE;
262 packet.length = htons(plen);
264 sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
267 /**********************************************************************
268 *%FUNCTION: waitForPADO
270 * conn -- PPPoEConnection structure
271 * timeout -- how long to wait (in seconds)
275 * Waits for a PADO packet and copies useful information
276 ***********************************************************************/
278 waitForPADO(PPPoEConnection *conn, int timeout)
286 struct PacketCriteria pc;
288 pc.acNameOK = (conn->acName) ? 0 : 1;
289 pc.serviceNameOK = (conn->serviceName) ? 0 : 1;
291 pc.seenServiceName = 0;
295 if (BPF_BUFFER_IS_EMPTY) {
300 FD_SET(conn->discoverySocket, &readable);
303 r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
304 if (r >= 0 || errno != EINTR) break;
307 error("select (waitForPADO): %m");
310 if (r == 0) return; /* Timed out */
314 receivePacket(conn->discoverySocket, &packet, &len);
317 if (ntohs(packet.length) + HDR_SIZE > len) {
318 error("Bogus PPPoE length field (%u)",
319 (unsigned int) ntohs(packet.length));
324 /* If it's not a Discovery packet, loop again */
325 if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
328 /* If it's not for us, loop again */
329 if (!packetIsForMe(conn, &packet)) continue;
331 if (packet.code == CODE_PADO) {
332 if (NOT_UNICAST(packet.ethHdr.h_source)) {
333 error("Ignoring PADO packet from non-unicast MAC address");
337 && memcmp(packet.ethHdr.h_source, conn->req_peer_mac, ETH_ALEN) != 0) {
338 warn("Ignoring PADO packet from wrong MAC address");
341 if (parsePacket(&packet, parsePADOTags, &pc) < 0)
345 if (!pc.seenACName) {
346 error("Ignoring PADO packet with no AC-Name tag");
349 if (!pc.seenServiceName) {
350 error("Ignoring PADO packet with no Service-Name tag");
354 if (pc.acNameOK && pc.serviceNameOK) {
355 memcpy(conn->peerEth, packet.ethHdr.h_source, ETH_ALEN);
356 conn->discoveryState = STATE_RECEIVED_PADO;
360 } while (conn->discoveryState != STATE_RECEIVED_PADO);
363 /***********************************************************************
366 * conn -- PPPoE connection structur
370 * Sends a PADR packet
371 ***********************************************************************/
373 sendPADR(PPPoEConnection *conn)
376 PPPoETag *svc = (PPPoETag *) packet.payload;
377 unsigned char *cursor = packet.payload;
379 UINT16_t namelen = 0;
382 if (conn->serviceName) {
383 namelen = (UINT16_t) strlen(conn->serviceName);
385 plen = TAG_HDR_SIZE + namelen;
386 CHECK_ROOM(cursor, packet.payload, plen);
388 memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN);
389 memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
391 packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
392 packet.vertype = PPPOE_VER_TYPE(1, 1);
393 packet.code = CODE_PADR;
396 svc->type = TAG_SERVICE_NAME;
397 svc->length = htons(namelen);
398 if (conn->serviceName) {
399 memcpy(svc->payload, conn->serviceName, namelen);
401 cursor += namelen + TAG_HDR_SIZE;
403 /* If we're using Host-Uniq, copy it over */
404 if (conn->useHostUniq) {
406 pid_t pid = getpid();
407 hostUniq.type = htons(TAG_HOST_UNIQ);
408 hostUniq.length = htons(sizeof(pid));
409 memcpy(hostUniq.payload, &pid, sizeof(pid));
410 CHECK_ROOM(cursor, packet.payload, sizeof(pid)+TAG_HDR_SIZE);
411 memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
412 cursor += sizeof(pid) + TAG_HDR_SIZE;
413 plen += sizeof(pid) + TAG_HDR_SIZE;
416 /* Copy cookie and relay-ID if needed */
417 if (conn->cookie.type) {
418 CHECK_ROOM(cursor, packet.payload,
419 ntohs(conn->cookie.length) + TAG_HDR_SIZE);
420 memcpy(cursor, &conn->cookie, ntohs(conn->cookie.length) + TAG_HDR_SIZE);
421 cursor += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
422 plen += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
425 if (conn->relayId.type) {
426 CHECK_ROOM(cursor, packet.payload,
427 ntohs(conn->relayId.length) + TAG_HDR_SIZE);
428 memcpy(cursor, &conn->relayId, ntohs(conn->relayId.length) + TAG_HDR_SIZE);
429 cursor += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
430 plen += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
433 packet.length = htons(plen);
434 sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
437 /**********************************************************************
438 *%FUNCTION: waitForPADS
440 * conn -- PPPoE connection info
441 * timeout -- how long to wait (in seconds)
445 * Waits for a PADS packet and copies useful information
446 ***********************************************************************/
448 waitForPADS(PPPoEConnection *conn, int timeout)
458 if (BPF_BUFFER_IS_EMPTY) {
463 FD_SET(conn->discoverySocket, &readable);
466 r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
467 if (r >= 0 || errno != EINTR) break;
470 error("select (waitForPADS): %m");
477 receivePacket(conn->discoverySocket, &packet, &len);
480 if (ntohs(packet.length) + HDR_SIZE > len) {
481 error("Bogus PPPoE length field (%u)",
482 (unsigned int) ntohs(packet.length));
487 /* If it's not a Discovery packet, loop again */
488 if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
491 /* If it's not from the AC, it's not for me */
492 if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) continue;
494 /* If it's not for us, loop again */
495 if (!packetIsForMe(conn, &packet)) continue;
498 if (packet.code == CODE_PADS) {
499 /* Parse for goodies */
500 if (parsePacket(&packet, parsePADSTags, conn) < 0)
504 conn->discoveryState = STATE_SESSION;
507 } while (conn->discoveryState != STATE_SESSION);
509 /* Don't bother with ntohs; we'll just end up converting it back... */
510 conn->session = packet.session;
512 info("PPP session is %d", (int) ntohs(conn->session));
514 /* RFC 2516 says session id MUST NOT be zero or 0xFFFF */
515 if (ntohs(conn->session) == 0 || ntohs(conn->session) == 0xFFFF) {
516 error("Access concentrator used a session value of %x -- the AC is violating RFC 2516", (unsigned int) ntohs(conn->session));
520 /**********************************************************************
521 *%FUNCTION: discovery
523 * conn -- PPPoE connection info structure
527 * Performs the PPPoE discovery phase
528 ***********************************************************************/
530 discovery(PPPoEConnection *conn)
532 int padiAttempts = 0;
533 int padrAttempts = 0;
534 int timeout = conn->discoveryTimeout;
536 conn->discoverySocket =
537 openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth);
541 if (padiAttempts > MAX_PADI_ATTEMPTS) {
542 warn("Timeout waiting for PADO packets");
543 close(conn->discoverySocket);
544 conn->discoverySocket = -1;
548 conn->discoveryState = STATE_SENT_PADI;
549 waitForPADO(conn, timeout);
552 } while (conn->discoveryState == STATE_SENT_PADI);
554 timeout = conn->discoveryTimeout;
557 if (padrAttempts > MAX_PADI_ATTEMPTS) {
558 warn("Timeout waiting for PADS packets");
559 close(conn->discoverySocket);
560 conn->discoverySocket = -1;
564 conn->discoveryState = STATE_SENT_PADR;
565 waitForPADS(conn, timeout);
567 } while (conn->discoveryState == STATE_SENT_PADR);
570 conn->discoveryState = STATE_SESSION;