X-Git-Url: https://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Fplugins%2Frp-pppoe%2Fdiscovery.c;h=fd851def2fededf5f53bb64fd7681406ad598fcf;hp=6e25ae7361e9167b7f1ab01f58b4ba8e6d1d584c;hb=c319558b8cacad7d27f04c7d612e44b67f273434;hpb=76307d910b81acb709143b2fd82e1ca724feb24c diff --git a/pppd/plugins/rp-pppoe/discovery.c b/pppd/plugins/rp-pppoe/discovery.c index 6e25ae7..fd851de 100644 --- a/pppd/plugins/rp-pppoe/discovery.c +++ b/pppd/plugins/rp-pppoe/discovery.c @@ -14,6 +14,8 @@ static char const RCSID[] = #define _GNU_SOURCE 1 #include "pppoe.h" #include "pppd/pppd.h" +#include "pppd/fsm.h" +#include "pppd/lcp.h" #include #include @@ -38,6 +40,30 @@ static char const RCSID[] = #include +/* Calculate time remaining until *exp, return 0 if now >= *exp */ +static int time_left(struct timeval *diff, struct timeval *exp) +{ + struct timeval now; + + if (get_time(&now) < 0) { + error("get_time: %m"); + return 0; + } + + if (now.tv_sec > exp->tv_sec + || (now.tv_sec == exp->tv_sec && now.tv_usec >= exp->tv_usec)) + return 0; + + diff->tv_sec = exp->tv_sec - now.tv_sec; + diff->tv_usec = exp->tv_usec - now.tv_usec; + if (diff->tv_usec < 0) { + diff->tv_usec += 1000000; + --diff->tv_sec; + } + + return 1; +} + /********************************************************************** *%FUNCTION: parseForHostUniq *%ARGUMENTS: @@ -54,14 +80,10 @@ static void parseForHostUniq(UINT16_t type, UINT16_t len, unsigned char *data, void *extra) { - int *val = (int *) extra; - if (type == TAG_HOST_UNIQ && len == sizeof(pid_t)) { - pid_t tmp; - memcpy(&tmp, data, len); - if (tmp == getpid()) { - *val = 1; - } - } + PPPoETag *tag = extra; + + if (type == TAG_HOST_UNIQ && len == ntohs(tag->length)) + tag->length = memcmp(data, tag->payload, len); } /********************************************************************** @@ -78,16 +100,16 @@ parseForHostUniq(UINT16_t type, UINT16_t len, unsigned char *data, static int packetIsForMe(PPPoEConnection *conn, PPPoEPacket *packet) { - int forMe = 0; + PPPoETag hostUniq = conn->hostUniq; /* If packet is not directed to our MAC address, forget it */ if (memcmp(packet->ethHdr.h_dest, conn->myEth, ETH_ALEN)) return 0; /* If we're not using the Host-Unique tag, then accept the packet */ - if (!conn->useHostUniq) return 1; + if (!conn->hostUniq.length) return 1; - parsePacket(packet, parseForHostUniq, &forMe); - return forMe; + parsePacket(packet, parseForHostUniq, &hostUniq); + return !hostUniq.length; } /********************************************************************** @@ -110,6 +132,7 @@ parsePADOTags(UINT16_t type, UINT16_t len, unsigned char *data, { struct PacketCriteria *pc = (struct PacketCriteria *) extra; PPPoEConnection *conn = pc->conn; + UINT16_t mru; int i; switch(type) { @@ -140,6 +163,19 @@ parsePADOTags(UINT16_t type, UINT16_t len, unsigned char *data, conn->relayId.length = htons(len); memcpy(conn->relayId.payload, data, len); break; + case TAG_PPP_MAX_PAYLOAD: + if (len == sizeof(mru)) { + memcpy(&mru, data, sizeof(mru)); + mru = ntohs(mru); + if (mru >= ETH_PPPOE_MTU) { + if (lcp_allowoptions[0].mru > mru) + lcp_allowoptions[0].mru = mru; + if (lcp_wantoptions[0].mru > mru) + lcp_wantoptions[0].mru = mru; + conn->seenMaxPayload = 1; + } + } + break; case TAG_SERVICE_NAME_ERROR: error("PADO: Service-Name-Error: %.*s", (int) len, data); conn->error = 1; @@ -172,10 +208,24 @@ parsePADSTags(UINT16_t type, UINT16_t len, unsigned char *data, void *extra) { PPPoEConnection *conn = (PPPoEConnection *) extra; + UINT16_t mru; switch(type) { case TAG_SERVICE_NAME: dbglog("PADS: Service-Name: '%.*s'", (int) len, data); break; + case TAG_PPP_MAX_PAYLOAD: + if (len == sizeof(mru)) { + memcpy(&mru, data, sizeof(mru)); + mru = ntohs(mru); + if (mru >= ETH_PPPOE_MTU) { + if (lcp_allowoptions[0].mru > mru) + lcp_allowoptions[0].mru = mru; + if (lcp_wantoptions[0].mru > mru) + lcp_wantoptions[0].mru = mru; + conn->seenMaxPayload = 1; + } + } + break; case TAG_SERVICE_NAME_ERROR: error("PADS: Service-Name-Error: %.*s", (int) len, data); conn->error = 1; @@ -247,16 +297,25 @@ sendPADI(PPPoEConnection *conn) } /* If we're using Host-Uniq, copy it over */ - if (conn->useHostUniq) { - PPPoETag hostUniq; - pid_t pid = getpid(); - hostUniq.type = htons(TAG_HOST_UNIQ); - hostUniq.length = htons(sizeof(pid)); - memcpy(hostUniq.payload, &pid, sizeof(pid)); - CHECK_ROOM(cursor, packet.payload, sizeof(pid) + TAG_HDR_SIZE); - memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE); - cursor += sizeof(pid) + TAG_HDR_SIZE; - plen += sizeof(pid) + TAG_HDR_SIZE; + if (conn->hostUniq.length) { + int len = ntohs(conn->hostUniq.length); + CHECK_ROOM(cursor, packet.payload, len + TAG_HDR_SIZE); + memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE); + cursor += len + TAG_HDR_SIZE; + plen += len + TAG_HDR_SIZE; + } + + /* Add our maximum MTU/MRU */ + if (MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru) > ETH_PPPOE_MTU) { + PPPoETag maxPayload; + UINT16_t mru = htons(MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru)); + maxPayload.type = htons(TAG_PPP_MAX_PAYLOAD); + maxPayload.length = htons(sizeof(mru)); + memcpy(maxPayload.payload, &mru, sizeof(mru)); + CHECK_ROOM(cursor, packet.payload, sizeof(mru) + TAG_HDR_SIZE); + memcpy(cursor, &maxPayload, sizeof(mru) + TAG_HDR_SIZE); + cursor += sizeof(mru) + TAG_HDR_SIZE; + plen += sizeof(mru) + TAG_HDR_SIZE; } packet.length = htons(plen); @@ -280,6 +339,8 @@ waitForPADO(PPPoEConnection *conn, int timeout) fd_set readable; int r; struct timeval tv; + struct timeval expire_at; + PPPoEPacket packet; int len; @@ -289,25 +350,33 @@ waitForPADO(PPPoEConnection *conn, int timeout) pc.serviceNameOK = (conn->serviceName) ? 0 : 1; pc.seenACName = 0; pc.seenServiceName = 0; + conn->seenMaxPayload = 0; conn->error = 0; + if (get_time(&expire_at) < 0) { + error("get_time (waitForPADO): %m"); + return; + } + expire_at.tv_sec += timeout; + do { if (BPF_BUFFER_IS_EMPTY) { - tv.tv_sec = timeout; - tv.tv_usec = 0; + if (!time_left(&tv, &expire_at)) + return; /* Timed out */ FD_ZERO(&readable); FD_SET(conn->discoverySocket, &readable); while(1) { r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv); - if (r >= 0 || errno != EINTR) break; + if (r >= 0 || errno != EINTR || got_sigterm) break; } if (r < 0) { error("select (waitForPADO): %m"); return; } - if (r == 0) return; /* Timed out */ + if (r == 0) + return; /* Timed out */ } /* Get the packet */ @@ -401,16 +470,25 @@ sendPADR(PPPoEConnection *conn) cursor += namelen + TAG_HDR_SIZE; /* If we're using Host-Uniq, copy it over */ - if (conn->useHostUniq) { - PPPoETag hostUniq; - pid_t pid = getpid(); - hostUniq.type = htons(TAG_HOST_UNIQ); - hostUniq.length = htons(sizeof(pid)); - memcpy(hostUniq.payload, &pid, sizeof(pid)); - CHECK_ROOM(cursor, packet.payload, sizeof(pid)+TAG_HDR_SIZE); - memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE); - cursor += sizeof(pid) + TAG_HDR_SIZE; - plen += sizeof(pid) + TAG_HDR_SIZE; + if (conn->hostUniq.length) { + int len = ntohs(conn->hostUniq.length); + CHECK_ROOM(cursor, packet.payload, len+TAG_HDR_SIZE); + memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE); + cursor += len + TAG_HDR_SIZE; + plen += len + TAG_HDR_SIZE; + } + + /* Add our maximum MTU/MRU */ + if (MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru) > ETH_PPPOE_MTU) { + PPPoETag maxPayload; + UINT16_t mru = htons(MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru)); + maxPayload.type = htons(TAG_PPP_MAX_PAYLOAD); + maxPayload.length = htons(sizeof(mru)); + memcpy(maxPayload.payload, &mru, sizeof(mru)); + CHECK_ROOM(cursor, packet.payload, sizeof(mru) + TAG_HDR_SIZE); + memcpy(cursor, &maxPayload, sizeof(mru) + TAG_HDR_SIZE); + cursor += sizeof(mru) + TAG_HDR_SIZE; + plen += sizeof(mru) + TAG_HDR_SIZE; } /* Copy cookie and relay-ID if needed */ @@ -450,27 +528,36 @@ waitForPADS(PPPoEConnection *conn, int timeout) fd_set readable; int r; struct timeval tv; + struct timeval expire_at; + PPPoEPacket packet; int len; + if (get_time(&expire_at) < 0) { + error("get_time (waitForPADS): %m"); + return; + } + expire_at.tv_sec += timeout; + conn->error = 0; do { if (BPF_BUFFER_IS_EMPTY) { - tv.tv_sec = timeout; - tv.tv_usec = 0; + if (!time_left(&tv, &expire_at)) + return; /* Timed out */ FD_ZERO(&readable); FD_SET(conn->discoverySocket, &readable); while(1) { r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv); - if (r >= 0 || errno != EINTR) break; + if (r >= 0 || errno != EINTR || got_sigterm) break; } if (r < 0) { error("select (waitForPADS): %m"); return; } - if (r == 0) return; + if (r == 0) + return; /* Timed out */ } /* Get the packet */ @@ -533,12 +620,9 @@ discovery(PPPoEConnection *conn) int padrAttempts = 0; int timeout = conn->discoveryTimeout; - conn->discoverySocket = - openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth); - do { padiAttempts++; - if (padiAttempts > MAX_PADI_ATTEMPTS) { + if (got_sigterm || padiAttempts > conn->discoveryAttempts) { warn("Timeout waiting for PADO packets"); close(conn->discoverySocket); conn->discoverySocket = -1; @@ -554,7 +638,7 @@ discovery(PPPoEConnection *conn) timeout = conn->discoveryTimeout; do { padrAttempts++; - if (padrAttempts > MAX_PADI_ATTEMPTS) { + if (got_sigterm || padrAttempts > conn->discoveryAttempts) { warn("Timeout waiting for PADS packets"); close(conn->discoverySocket); conn->discoverySocket = -1; @@ -566,6 +650,14 @@ discovery(PPPoEConnection *conn) timeout *= 2; } while (conn->discoveryState == STATE_SENT_PADR); + if (!conn->seenMaxPayload) { + /* RFC 4638: MUST limit MTU/MRU to 1492 */ + if (lcp_allowoptions[0].mru > ETH_PPPOE_MTU) + lcp_allowoptions[0].mru = ETH_PPPOE_MTU; + if (lcp_wantoptions[0].mru > ETH_PPPOE_MTU) + lcp_wantoptions[0].mru = ETH_PPPOE_MTU; + } + /* We're done. */ conn->discoveryState = STATE_SESSION; return;