summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--accel-pptpd/ctrl/CMakeLists.txt1
-rw-r--r--accel-pptpd/ctrl/pppoe.c884
-rw-r--r--accel-pptpd/ctrl/pppoe.h59
-rw-r--r--accel-pptpd/include/events.h2
-rw-r--r--accel-pptpd/include/if_pppox.h13
-rw-r--r--accel-pptpd/ppp/ppp.c2
-rw-r--r--accel-pptpd/ppp/ppp_ccp.c2
-rw-r--r--accel-pptpd/ppp/ppp_fsm.c6
-rw-r--r--accel-pptpd/ppp/ppp_ipcp.c2
-rw-r--r--rfc/rfc2516.txt955
10 files changed, 1920 insertions, 6 deletions
diff --git a/accel-pptpd/ctrl/CMakeLists.txt b/accel-pptpd/ctrl/CMakeLists.txt
index 53b0dc1..c26bdd5 100644
--- a/accel-pptpd/ctrl/CMakeLists.txt
+++ b/accel-pptpd/ctrl/CMakeLists.txt
@@ -1,6 +1,7 @@
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
ADD_LIBRARY(pptp SHARED pptp.c)
+ADD_LIBRARY(pppoe SHARED pppoe.c)
INSTALL(TARGETS pptp
LIBRARY DESTINATION usr/lib/accel-pptp
diff --git a/accel-pptpd/ctrl/pppoe.c b/accel-pptpd/ctrl/pppoe.c
new file mode 100644
index 0000000..7a9616a
--- /dev/null
+++ b/accel-pptpd/ctrl/pppoe.c
@@ -0,0 +1,884 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/ethernet.h>
+#include <netpacket/packet.h>
+#include <arpa/inet.h>
+
+#include <openssl/md5.h>
+
+#include "events.h"
+#include "triton.h"
+#include "log.h"
+#include "ppp.h"
+#include "mempool.h"
+
+#include "pppoe.h"
+
+#include "memdebug.h"
+
+
+struct pppoe_serv_t
+{
+ struct triton_context_t ctx;
+ struct triton_md_handler_t hnd;
+ uint8_t hwaddr[ETH_ALEN];
+ const char *ifname;
+
+ pthread_mutex_t lock;
+ struct pppoe_conn_t *conn[MAX_SID];
+ uint16_t sid;
+};
+
+struct pppoe_conn_t
+{
+ struct triton_context_t ctx;
+ struct pppoe_serv_t *serv;
+ int disc_sock;
+ uint16_t sid;
+ uint8_t addr[ETH_ALEN];
+ int ppp_started:1;
+
+ struct pppoe_tag *relay_sid;
+ struct pppoe_tag *host_uniq;
+
+ struct ppp_ctrl_t ctrl;
+ struct ppp_t ppp;
+};
+
+static int conf_verbose = 0;
+static const char *conf_service_name = "";
+static const char *conf_ac_name = "accel-pptp";
+
+static mempool_t conn_pool;
+
+#define SECRET_SIZE 16
+static uint8_t *secret;
+
+static uint8_t bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+static void pppoe_send_PADT(struct pppoe_conn_t *conn);
+
+static void disconnect(struct pppoe_conn_t *conn)
+{
+ if (conn->ppp_started) {
+ conn->ppp_started = 0;
+ ppp_terminate(&conn->ppp, 1);
+ }
+
+ pppoe_send_PADT(conn);
+
+ close(conn->disc_sock);
+
+ triton_event_fire(EV_CTRL_FINISHED, &conn->ppp);
+
+ if (conf_verbose)
+ log_ppp_info("disconnected\n");
+
+ pthread_mutex_lock(&conn->serv->lock);
+ conn->serv->conn[conn->sid] = NULL;
+ pthread_mutex_unlock(&conn->serv->lock);
+
+ _free(conn->ctrl.calling_station_id);
+ _free(conn->ctrl.called_station_id);
+ if (conn->host_uniq)
+ _free(conn->host_uniq);
+ if (conn->relay_sid)
+ _free(conn->relay_sid);
+
+ triton_context_unregister(&conn->ctx);
+
+ mempool_free(conn);
+}
+
+static void ppp_started(struct ppp_t *ppp)
+{
+ log_ppp_debug("pppoe: ppp started\n");
+}
+
+static void ppp_finished(struct ppp_t *ppp)
+{
+ struct pppoe_conn_t *conn = container_of(ppp, typeof(*conn), ppp);
+
+ log_ppp_debug("pppoe: ppp finished\n");
+
+ if (conn->ppp_started) {
+ conn->ppp_started = 0;
+ disconnect(conn);
+ }
+}
+
+static void pppoe_conn_close(struct triton_context_t *ctx)
+{
+ struct pppoe_conn_t *conn = container_of(ctx, typeof(*conn), ctx);
+
+ if (conn->ppp_started)
+ ppp_terminate(&conn->ppp, 0);
+ else
+ disconnect(conn);
+}
+
+static struct pppoe_conn_t *allocate_channel(struct pppoe_serv_t *serv, const uint8_t *addr, const struct pppoe_tag *host_uniq, const struct pppoe_tag *relay_sid)
+{
+ struct pppoe_conn_t *conn;
+ int sid;
+
+ conn = mempool_alloc(conn_pool);
+ if (!conn) {
+ log_emerg("pppoe: out of memory\n");
+ return NULL;
+ }
+
+ memset(conn, 0, sizeof(*conn));
+
+ pthread_mutex_lock(&serv->lock);
+ for (sid = serv->sid + 1; sid != serv->sid; sid++) {
+ if (sid == MAX_SID)
+ sid = 1;
+ if (!serv->conn[sid]) {
+ conn->sid = sid;
+ serv->sid = sid;
+ serv->conn[sid] = conn;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&serv->lock);
+
+ if (!conn->sid) {
+ log_warn("pppoe: no free sid available\n");
+ mempool_free(conn);
+ return NULL;
+ }
+
+ conn->serv = serv;
+ memcpy(conn->addr, addr, ETH_ALEN);
+
+ if (host_uniq) {
+ conn->host_uniq = _malloc(sizeof(*host_uniq) + ntohs(host_uniq->tag_len));
+ memcpy(conn->host_uniq, host_uniq, sizeof(*host_uniq) + ntohs(host_uniq->tag_len));
+ }
+
+ if (relay_sid) {
+ conn->relay_sid = _malloc(sizeof(*relay_sid) + ntohs(relay_sid->tag_len));
+ memcpy(conn->relay_sid, relay_sid, sizeof(*relay_sid) + ntohs(relay_sid->tag_len));
+ }
+
+ conn->ctx.close = pppoe_conn_close;
+ conn->ctrl.ctx = &conn->ctx;
+ conn->ctrl.started = ppp_started;
+ conn->ctrl.finished = ppp_finished;
+ conn->ctrl.max_mtu = MAX_PPPOE_MTU;
+ conn->ctrl.name = "pppoe";
+
+ conn->ctrl.calling_station_id = _malloc(19);
+ conn->ctrl.called_station_id = _malloc(19);
+ sprintf(conn->ctrl.calling_station_id, "%02x:%02x:%02x:%02x:%02x:%02x",
+ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+ sprintf(conn->ctrl.called_station_id, "%02x:%02x:%02x:%02x:%02x:%02x",
+ serv->hwaddr[0], serv->hwaddr[1], serv->hwaddr[2], serv->hwaddr[3], serv->hwaddr[4], serv->hwaddr[5]);
+
+ ppp_init(&conn->ppp);
+
+ conn->ppp.ctrl = &conn->ctrl;
+ conn->ppp.chan_name = conn->ctrl.calling_station_id;
+
+ triton_context_register(&conn->ctx, &conn->ppp);
+ triton_context_wakeup(&conn->ctx);
+
+ triton_event_fire(EV_CTRL_STARTING, &conn->ppp);
+ triton_event_fire(EV_CTRL_STARTED, &conn->ppp);
+
+ conn->disc_sock = dup(serv->hnd.fd);
+
+ return conn;
+}
+
+static int connect_channel(struct pppoe_conn_t *conn)
+{
+ int sock;
+ struct sockaddr_pppox sp;
+
+ sock = socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_OE);
+ if (!sock) {
+ log_error("pppoe: socket(PPPOX): %s\n", strerror(errno));
+ return -1;
+ }
+
+ memset(&sp, 0, sizeof(sp));
+
+ sp.sa_family = AF_PPPOX;
+ sp.sa_protocol = PX_PROTO_OE;
+ sp.sa_addr.pppoe.sid = htons(conn->sid);
+ strcpy(sp.sa_addr.pppoe.dev, conn->serv->ifname);
+ memcpy(sp.sa_addr.pppoe.remote, conn->addr, ETH_ALEN);
+
+ if (connect(sock, (struct sockaddr *)&sp, sizeof(sp))) {
+ log_error("pppoe: connect: %s\n", strerror(errno));
+ close(sock);
+ return -1;
+ }
+
+ conn->ppp.fd = sock;
+
+ if (establish_ppp(&conn->ppp)) {
+ close(sock);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void print_tag_string(struct pppoe_tag *tag)
+{
+ int i;
+
+ for (i = 0; i < ntohs(tag->tag_len); i++)
+ log_info("%c", tag->tag_data[i]);
+}
+
+static void print_tag_octets(struct pppoe_tag *tag)
+{
+ int i;
+
+ for (i = 0; i < ntohs(tag->tag_len); i++)
+ log_info("%02x", (uint8_t)tag->tag_data[i]);
+}
+
+static void print_packet(uint8_t *pack)
+{
+ struct ethhdr *ethhdr = (struct ethhdr *)pack;
+ struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN);
+ struct pppoe_tag *tag;
+ int n;
+
+ log_info("[PPPoE ");
+
+ switch (hdr->code) {
+ case CODE_PADI:
+ log_info("PADI");
+ break;
+ case CODE_PADO:
+ log_info("PADO");
+ break;
+ case CODE_PADR:
+ log_info("PADR");
+ break;
+ case CODE_PADS:
+ log_info("PADS");
+ break;
+ case CODE_PADT:
+ log_info("PADT");
+ break;
+ }
+
+ log_info(" %02x:%02x:%02x:%02x:%02x:%02x => %02x:%02x:%02x:%02x:%02x:%02x",
+ ethhdr->h_source[0], ethhdr->h_source[1], ethhdr->h_source[2], ethhdr->h_source[3], ethhdr->h_source[4], ethhdr->h_source[5],
+ ethhdr->h_dest[0], ethhdr->h_dest[1], ethhdr->h_dest[2], ethhdr->h_dest[3], ethhdr->h_dest[4], ethhdr->h_dest[5]);
+
+ log_info(" sid=%04x", ntohs(hdr->sid));
+
+ for (n = 0; n < ntohs(hdr->length); n += sizeof(*tag) + ntohs(tag->tag_len)) {
+ tag = (struct pppoe_tag *)(pack + ETH_HLEN + sizeof(*hdr) + n);
+ switch (ntohs(tag->tag_type)) {
+ case TAG_END_OF_LIST:
+ log_info(" <End-Of-List>");
+ break;
+ case TAG_SERVICE_NAME:
+ log_info(" <Service-Name ");
+ print_tag_string(tag);
+ log_info(">");
+ break;
+ case TAG_AC_NAME:
+ log_info(" <AC-Name ");
+ print_tag_string(tag);
+ log_info(">");
+ break;
+ case TAG_HOST_UNIQ:
+ log_info(" <Host-Uniq ");
+ print_tag_octets(tag);
+ log_info(">");
+ break;
+ case TAG_AC_COOKIE:
+ log_info(" <AC-Cookie ");
+ print_tag_octets(tag);
+ log_info(">");
+ break;
+ case TAG_VENDOR_SPECIFIC:
+ log_info(" <Vendor-Specific>");
+ break;
+ case TAG_RELAY_SESSION_ID:
+ log_info(" <Relay-Session-Id");
+ print_tag_octets(tag);
+ log_info(">");
+ break;
+ case TAG_SERVICE_NAME_ERROR:
+ log_info(" <Service-Name-Error>");
+ break;
+ case TAG_AC_SYSTEM_ERROR:
+ log_info(" <AC-System-Error>");
+ break;
+ case TAG_GENERIC_ERROR:
+ log_info(" <Generic-Error>");
+ break;
+ default:
+ log_info(" <Unknown (%x)>", ntohs(tag->tag_type));
+ break;
+ }
+ }
+
+ log_info("]\n");
+}
+
+static void generate_cookie(const uint8_t *src, const uint8_t *dst, const struct pppoe_tag *host_uniq, uint8_t *cookie)
+{
+ MD5_CTX ctx;
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, secret, SECRET_SIZE);
+ MD5_Update(&ctx, src, ETH_ALEN);
+ MD5_Update(&ctx, dst, ETH_ALEN);
+ if (host_uniq)
+ MD5_Update(&ctx, host_uniq->tag_data, ntohs(host_uniq->tag_len));
+ MD5_Update(&ctx, conf_ac_name, strlen(conf_ac_name));
+ MD5_Update(&ctx, secret, SECRET_SIZE);
+ MD5_Final(cookie, &ctx);
+}
+
+static void setup_header(uint8_t *pack, const uint8_t *src, const uint8_t *dst, int code, uint16_t sid)
+{
+ struct ethhdr *ethhdr = (struct ethhdr *)pack;
+ struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN);
+
+ memcpy(ethhdr->h_source, src, ETH_ALEN);
+ memcpy(ethhdr->h_dest, dst, ETH_ALEN);
+ ethhdr->h_proto = htons(ETH_P_PPP_DISC);
+
+ hdr->ver = 1;
+ hdr->type = 1;
+ hdr->code = code;
+ hdr->sid = htons(sid);
+ hdr->length = 0;
+}
+
+static void add_tag(uint8_t *pack, int type, const uint8_t *data, int len)
+{
+ struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN);
+ struct pppoe_tag *tag = (struct pppoe_tag *)(pack + ETH_HLEN + sizeof(*hdr) + ntohs(hdr->length));
+
+ tag->tag_type = htons(type);
+ tag->tag_len = htons(len);
+ memcpy(tag->tag_data, data, len);
+
+ hdr->length = htons(ntohs(hdr->length) + sizeof(*tag) + len);
+}
+
+static void add_tag2(uint8_t *pack, const struct pppoe_tag *t)
+{
+ struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN);
+ struct pppoe_tag *tag = (struct pppoe_tag *)(pack + ETH_HLEN + sizeof(*hdr) + ntohs(hdr->length));
+
+ memcpy(tag, t, sizeof(*t) + ntohs(t->tag_len));
+
+ hdr->length = htons(ntohs(hdr->length) + sizeof(*tag) + ntohs(t->tag_len));
+}
+
+static void pppoe_send(int fd, const uint8_t *pack)
+{
+ struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN);
+ int n, s;
+
+ s = ETH_HLEN + sizeof(*hdr) + ntohs(hdr->length);
+ n = write(fd, pack, s);
+ if (n < 0 )
+ log_error("pppoe: write: %s\n", strerror(errno));
+ else if (n != s) {
+ log_warn("pppoe: short write %i/%i\n", n,s);
+ }
+}
+
+static void pppoe_send_PADO(struct pppoe_serv_t *serv, const uint8_t *addr, const struct pppoe_tag *host_uniq, const struct pppoe_tag *relay_sid)
+{
+ uint8_t pack[ETHER_MAX_LEN];
+ uint8_t cookie[MD5_DIGEST_LENGTH];
+
+ setup_header(pack, serv->hwaddr, addr, CODE_PADO, 0);
+
+ add_tag(pack, TAG_AC_NAME, (uint8_t *)conf_ac_name, strlen(conf_ac_name));
+ add_tag(pack, TAG_SERVICE_NAME, (uint8_t *)conf_service_name, strlen(conf_service_name));
+
+ generate_cookie(serv->hwaddr, addr, host_uniq, cookie);
+ add_tag(pack, TAG_AC_COOKIE, cookie, MD5_DIGEST_LENGTH);
+
+ if (host_uniq)
+ add_tag2(pack, host_uniq);
+
+ if (relay_sid)
+ add_tag2(pack, relay_sid);
+
+ if (conf_verbose) {
+ log_info("send ");
+ print_packet(pack);
+ }
+
+ pppoe_send(serv->hnd.fd, pack);
+}
+
+static void pppoe_send_err(struct pppoe_serv_t *serv, const uint8_t *addr, const struct pppoe_tag *host_uniq, const struct pppoe_tag *relay_sid, int code, int tag_type)
+{
+ uint8_t pack[ETHER_MAX_LEN];
+
+ setup_header(pack, serv->hwaddr, addr, code, 0);
+
+ add_tag(pack, TAG_AC_NAME, (uint8_t *)conf_ac_name, strlen(conf_ac_name));
+ add_tag(pack, tag_type, NULL, 0);
+
+ if (host_uniq)
+ add_tag2(pack, host_uniq);
+
+ if (relay_sid)
+ add_tag2(pack, relay_sid);
+
+ if (conf_verbose) {
+ log_info("send ");
+ print_packet(pack);
+ }
+
+ pppoe_send(serv->hnd.fd, pack);
+}
+
+static void pppoe_send_PADS(struct pppoe_conn_t *conn)
+{
+ uint8_t pack[ETHER_MAX_LEN];
+
+ setup_header(pack, conn->serv->hwaddr, conn->addr, CODE_PADS, conn->sid);
+
+ add_tag(pack, TAG_AC_NAME, (uint8_t *)conf_ac_name, strlen(conf_ac_name));
+ add_tag(pack, TAG_SERVICE_NAME, (uint8_t *)conf_service_name, strlen(conf_service_name));
+
+ if (conn->host_uniq)
+ add_tag2(pack, conn->host_uniq);
+
+ if (conn->relay_sid)
+ add_tag2(pack, conn->relay_sid);
+
+ if (conf_verbose) {
+ log_info("send ");
+ print_packet(pack);
+ }
+
+ pppoe_send(conn->disc_sock, pack);
+}
+
+static void pppoe_send_PADT(struct pppoe_conn_t *conn)
+{
+ uint8_t pack[ETHER_MAX_LEN];
+
+ setup_header(pack, conn->serv->hwaddr, conn->addr, CODE_PADT, conn->sid);
+
+ add_tag(pack, TAG_AC_NAME, (uint8_t *)conf_ac_name, strlen(conf_ac_name));
+ add_tag(pack, TAG_SERVICE_NAME, (uint8_t *)conf_service_name, strlen(conf_service_name));
+
+ if (conn->host_uniq)
+ add_tag2(pack, conn->host_uniq);
+
+ if (conn->relay_sid)
+ add_tag2(pack, conn->relay_sid);
+
+ if (conf_verbose) {
+ log_info("send ");
+ print_packet(pack);
+ }
+
+ pppoe_send(conn->disc_sock, pack);
+}
+
+static void pppoe_recv_PADI(struct pppoe_serv_t *serv, uint8_t *pack, int size)
+{
+ struct ethhdr *ethhdr = (struct ethhdr *)pack;
+ struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN);
+ struct pppoe_tag *tag;
+ struct pppoe_tag *host_uniq_tag = NULL;
+ struct pppoe_tag *relay_sid_tag = NULL;
+ int n, service_match = 0;
+
+ if (hdr->sid) {
+ log_warn("pppoe: discaring PADI packet (sid is not zero)\n");
+ return;
+ }
+
+ if (conf_verbose) {
+ log_info("recv ");
+ print_packet(pack);
+ }
+
+ for (n = 0; n < ntohs(hdr->length); n += sizeof(*tag) + ntohs(tag->tag_len)) {
+ tag = (struct pppoe_tag *)(pack + ETH_HLEN + sizeof(*hdr) + n);
+ switch (ntohs(tag->tag_type)) {
+ case TAG_END_OF_LIST:
+ break;
+ case TAG_SERVICE_NAME:
+ if (tag->tag_len == 0)
+ service_match = 1;
+ else if (conf_service_name) {
+ if (ntohs(tag->tag_len) != strlen(conf_service_name))
+ break;
+ if (memcmp(tag->tag_data, conf_service_name, ntohs(tag->tag_len)))
+ break;
+ service_match = 1;
+ }
+ break;
+ case TAG_HOST_UNIQ:
+ host_uniq_tag = tag;
+ break;
+ case TAG_RELAY_SESSION_ID:
+ relay_sid_tag = tag;
+ break;
+ }
+ }
+
+ if (!service_match) {
+ if (conf_verbose)
+ log_warn("pppoe: discarding PADI packet (Service-Name mismatch)\n");
+ return;
+ }
+
+ pppoe_send_PADO(serv, ethhdr->h_source, host_uniq_tag, relay_sid_tag);
+}
+
+static void pppoe_recv_PADR(struct pppoe_serv_t *serv, uint8_t *pack, int size)
+{
+ struct ethhdr *ethhdr = (struct ethhdr *)pack;
+ struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN);
+ struct pppoe_tag *tag;
+ struct pppoe_tag *host_uniq_tag = NULL;
+ struct pppoe_tag *relay_sid_tag = NULL;
+ struct pppoe_tag *ac_cookie_tag = NULL;
+ uint8_t cookie[MD5_DIGEST_LENGTH];
+ int n, service_match = 0;
+ struct pppoe_conn_t *conn;
+
+ if (!memcmp(ethhdr->h_dest, bc_addr, ETH_ALEN)) {
+ if (conf_verbose)
+ log_warn("pppoe: discard PADR (destination address is broadcast)\n");
+ return;
+ }
+
+ if (hdr->sid) {
+ if (conf_verbose)
+ log_warn("pppoe: discaring PADR packet (sid is not zero)\n");
+ return;
+ }
+
+ if (conf_verbose) {
+ log_info("recv ");
+ print_packet(pack);
+ }
+
+ for (n = 0; n < ntohs(hdr->length); n += sizeof(*tag) + ntohs(tag->tag_len)) {
+ tag = (struct pppoe_tag *)(pack + ETH_HLEN + sizeof(*hdr) + n);
+ switch (ntohs(tag->tag_type)) {
+ case TAG_END_OF_LIST:
+ break;
+ case TAG_SERVICE_NAME:
+ if (tag->tag_len == 0)
+ service_match = 1;
+ else if (conf_service_name) {
+ if (ntohs(tag->tag_len) != strlen(conf_service_name))
+ break;
+ if (memcmp(tag->tag_data, conf_service_name, ntohs(tag->tag_len)))
+ break;
+ service_match = 1;
+ }
+ break;
+ case TAG_HOST_UNIQ:
+ host_uniq_tag = tag;
+ break;
+ case TAG_AC_COOKIE:
+ ac_cookie_tag = tag;
+ break;
+ case TAG_RELAY_SESSION_ID:
+ relay_sid_tag = tag;
+ break;
+ }
+ }
+
+ if (!ac_cookie_tag) {
+ if (conf_verbose)
+ log_warn("pppoe: discard PADR packet (no AC-Cookie tag present)\n");
+ return;
+ }
+
+ if (ntohs(ac_cookie_tag->tag_len) != MD5_DIGEST_LENGTH) {
+ if (conf_verbose)
+ log_warn("pppoe: discard PADR packet (incorrect AC-Cookie tag length)\n");
+ return;
+ }
+
+ generate_cookie(serv->hwaddr, ethhdr->h_source, host_uniq_tag, cookie);
+
+ if (memcmp(cookie, ac_cookie_tag->tag_data, MD5_DIGEST_LENGTH)) {
+ if (conf_verbose)
+ log_warn("pppoe: discard PADR packet (incorrect AC-Cookie)\n");
+ return;
+ }
+
+ if (!service_match) {
+ if (conf_verbose)
+ log_warn("pppoe: Service-Name mismatch\n");
+ pppoe_send_err(serv, ethhdr->h_source, host_uniq_tag, relay_sid_tag, CODE_PADS, TAG_SERVICE_NAME_ERROR);
+ return;
+ }
+
+ conn = allocate_channel(serv, ethhdr->h_source, host_uniq_tag, relay_sid_tag);
+ if (!conn)
+ pppoe_send_err(serv, ethhdr->h_source, host_uniq_tag, relay_sid_tag, CODE_PADS, TAG_AC_SYSTEM_ERROR);
+ else {
+ pppoe_send_PADS(conn);
+ if (connect_channel(conn))
+ disconnect(conn);
+ else
+ conn->ppp_started = 1;
+ }
+}
+
+static void pppoe_recv_PADT(struct pppoe_serv_t *serv, uint8_t *pack)
+{
+ struct ethhdr *ethhdr = (struct ethhdr *)pack;
+ struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN);
+ struct pppoe_conn_t *conn;
+
+ if (!memcmp(ethhdr->h_dest, bc_addr, ETH_ALEN)) {
+ if (conf_verbose)
+ log_warn("pppoe: discard PADT (destination address is broadcast)\n");
+ return;
+ }
+
+ if (conf_verbose) {
+ log_info("recv ");
+ print_packet(pack);
+ }
+
+ pthread_mutex_lock(&serv->lock);
+ conn = serv->conn[ntohs(hdr->sid)];
+ if (conn && !memcmp(conn->addr, ethhdr->h_source, ETH_ALEN))
+ triton_context_call(&conn->ctx, (void (*)(void *))disconnect, conn);
+ pthread_mutex_unlock(&serv->lock);
+}
+
+static int pppoe_serv_read(struct triton_md_handler_t *h)
+{
+ struct pppoe_serv_t *serv = container_of(h, typeof(*serv), hnd);
+ uint8_t pack[ETHER_MAX_LEN];
+ struct ethhdr *ethhdr = (struct ethhdr *)pack;
+ struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN);
+ int n;
+
+ n = read(h->fd, pack, sizeof(pack));
+ if (n < 0) {
+ log_error("pppoe: read: %s\n", strerror(errno));
+ return 0;
+ }
+
+ if (n < ETH_HLEN + sizeof(*hdr)) {
+ if (conf_verbose)
+ log_warn("pppoe: short packet received (%i)\n", n);
+ return 0;
+ }
+
+ if (memcmp(ethhdr->h_dest, bc_addr, ETH_ALEN) && memcmp(ethhdr->h_dest, serv->hwaddr, ETH_ALEN))
+ return 0;
+
+ if (!memcmp(ethhdr->h_source, bc_addr, ETH_ALEN)) {
+ if (conf_verbose)
+ log_warn("pppoe: discarding packet (host address is broadcast)\n");
+ return 0;
+ }
+
+ if ((ethhdr->h_source[0] & 1) != 0) {
+ if (conf_verbose)
+ log_warn("pppoe: discarding packet (host address is not unicast)\n");
+ return 0;
+ }
+
+ if (n < ETH_HLEN + sizeof(*hdr) + ntohs(hdr->length)) {
+ if (conf_verbose)
+ log_warn("pppoe: short packet received\n");
+ return 0;
+ }
+
+ if (hdr->ver != 1) {
+ if (conf_verbose)
+ log_warn("pppoe: discarding packet (unsupported version %i)\n", hdr->ver);
+ return 0;
+ }
+
+ if (hdr->type != 1) {
+ if (conf_verbose)
+ log_warn("pppoe: discarding packet (unsupported type %i)\n", hdr->type);
+ }
+
+ switch (hdr->code) {
+ case CODE_PADI:
+ pppoe_recv_PADI(serv, pack, n);
+ break;
+ case CODE_PADR:
+ pppoe_recv_PADR(serv, pack, n);
+ break;
+ case CODE_PADT:
+ pppoe_recv_PADT(serv, pack);
+ break;
+ }
+
+ return 0;
+}
+
+static void pppoe_serv_close(struct triton_context_t *ctx)
+{
+ struct pppoe_serv_t *serv = container_of(ctx, typeof(*serv), ctx);
+
+ triton_md_unregister_handler(&serv->hnd);
+ close(serv->hnd.fd);
+ triton_context_unregister(&serv->ctx);
+}
+
+static void pppoe_start_server(const char *ifname)
+{
+ struct pppoe_serv_t *serv = _malloc(sizeof(*serv));
+ int sock;
+ int opt = 1;
+ struct ifreq ifr;
+ struct sockaddr_ll sa;
+
+ memset(serv, 0, sizeof(*serv));
+
+ sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PPP_DISC));
+ if (sock < 0) {
+ log_emerg("pppoe: socket: %s\n", strerror(errno));
+ _free(serv);
+ return;
+ }
+
+ if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt))) {
+ log_emerg("pppoe: setsockopt(SO_BROADCAST): %s\n", strerror(errno));
+ goto out_err;
+ }
+
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(sock, SIOCGIFHWADDR, &ifr)) {
+ log_emerg("pppoe: ioctl(SIOCGIFHWADDR): %s\n", strerror(errno));
+ goto out_err;
+ }
+
+#ifdef ARPHDR_ETHER
+ if (ifr.ifr_hwaddr.sa_family != ARPHDR_ETHER) {
+ log_emerg("pppoe: interface %s is not ethernet\n", ifname);
+ goto out_err;
+ }
+#endif
+
+ if ((ifr.ifr_hwaddr.sa_data[0] & 1) != 0) {
+ log_emerg("pppoe: interface %s has not unicast address\n", ifname);
+ goto out_err;
+ }
+
+ memcpy(serv->hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ if (ioctl(sock, SIOCGIFMTU, &ifr)) {
+ log_emerg("pppoe: ioctl(SIOCGIFMTU): %s\n", strerror(errno));
+ goto out_err;
+ }
+
+ if (ifr.ifr_mtu < ETH_DATA_LEN)
+ log_emerg("pppoe: interface %s has MTU of %i, should be %i\n", ifname, ifr.ifr_mtu, ETH_DATA_LEN);
+
+ if (ioctl(sock, SIOCGIFINDEX, &ifr)) {
+ log_emerg("pppoe: ioctl(SIOCGIFINDEX): %s\n", strerror(errno));
+ goto out_err;
+ }
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sll_family = AF_PACKET;
+ sa.sll_protocol = htons(ETH_P_PPP_DISC);
+ sa.sll_ifindex = ifr.ifr_ifindex;
+
+ if (bind(sock, (struct sockaddr *)&sa, sizeof(sa))) {
+ log_emerg("pppoe: bind: %s\n", strerror(errno));
+ goto out_err;
+ }
+
+ serv->ctx.close = pppoe_serv_close;
+ serv->hnd.fd = sock;
+ serv->hnd.read = pppoe_serv_read;
+ serv->ifname = ifname;
+ pthread_mutex_init(&serv->lock, NULL);
+
+ triton_context_register(&serv->ctx, NULL);
+ triton_md_register_handler(&serv->ctx, &serv->hnd);
+ triton_md_enable_handler(&serv->hnd, MD_MODE_READ);
+ triton_context_wakeup(&serv->ctx);
+
+ return;
+
+out_err:
+ close(sock);
+ _free(serv);
+}
+
+static int init_secret(void)
+{
+ int fd;
+
+ secret = malloc(SECRET_SIZE);
+
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd < 0) {
+ log_emerg("pppoe: cann't open /dev/urandom: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (read(fd, secret, SECRET_SIZE) < 0) {
+ log_emerg("pppoe: faild to read /dev/urandom\n", strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+
+ return 0;
+}
+
+static void __init pppoe_init(void)
+{
+ struct conf_sect_t *s = conf_get_section("pppoe");
+ struct conf_option_t *opt;
+
+ conn_pool = mempool_create(sizeof(struct pppoe_conn_t));
+
+ if (init_secret())
+ _exit(EXIT_FAILURE);
+
+ if (!s) {
+ log_emerg("pppoe: no configuration, disabled...\n");
+ return;
+ }
+
+ list_for_each_entry(opt, &s->items, entry) {
+ if (!strcmp(opt->name, "interface"))
+ pppoe_start_server(opt->val);
+ else if (!strcmp(opt->name, "verbose")) {
+ if (atoi(opt->val) > 0)
+ conf_verbose = 1;
+ } else if (!strcmp(opt->name, "ac-name") || !strcmp(opt->name, "AC-Name"))
+ conf_ac_name = opt->val;
+ else if (!strcmp(opt->name, "service-name") || !strcmp(opt->name, "Service-Name"))
+ conf_service_name = opt->val;
+ }
+}
+
diff --git a/accel-pptpd/ctrl/pppoe.h b/accel-pptpd/ctrl/pppoe.h
new file mode 100644
index 0000000..0506108
--- /dev/null
+++ b/accel-pptpd/ctrl/pppoe.h
@@ -0,0 +1,59 @@
+#ifndef __PPPOE_H
+#define __PPPOE_H
+
+#include <linux/if.h>
+#include <linux/if_pppox.h>
+
+/* PPPoE codes */
+#define CODE_PADI 0x09
+#define CODE_PADO 0x07
+#define CODE_PADR 0x19
+#define CODE_PADS 0x65
+#define CODE_PADT 0xA7
+#define CODE_SESS 0x00
+
+/* PPPoE Tags */
+#define TAG_END_OF_LIST 0x0000
+#define TAG_SERVICE_NAME 0x0101
+#define TAG_AC_NAME 0x0102
+#define TAG_HOST_UNIQ 0x0103
+#define TAG_AC_COOKIE 0x0104
+#define TAG_VENDOR_SPECIFIC 0x0105
+#define TAG_RELAY_SESSION_ID 0x0110
+#define TAG_SERVICE_NAME_ERROR 0x0201
+#define TAG_AC_SYSTEM_ERROR 0x0202
+#define TAG_GENERIC_ERROR 0x0203
+
+/* Discovery phase states */
+#define STATE_SENT_PADI 0
+#define STATE_RECEIVED_PADO 1
+#define STATE_SENT_PADR 2
+#define STATE_SESSION 3
+#define STATE_TERMINATED 4
+
+/* Header size of a PPPoE packet */
+#define PPPOE_OVERHEAD 6 /* type, code, session, length */
+#define HDR_SIZE (sizeof(struct ethhdr) + PPPOE_OVERHEAD)
+#define MAX_PPPOE_PAYLOAD (ETH_DATA_LEN - PPPOE_OVERHEAD)
+#define MAX_PPPOE_MTU (MAX_PPPOE_PAYLOAD - 2)
+
+#define MAX_SID 65534
+
+struct pppoe_tag_t
+{
+ struct list_head entry;
+ int type;
+ int len;
+};
+
+struct pppoe_packet_t
+{
+ uint8_t src[ETH_ALEN];
+ uint8_t dst[ETH_ALEN];
+ int code;
+ uint16_t sid;
+ struct list_head tags;
+};
+
+#endif
+
diff --git a/accel-pptpd/include/events.h b/accel-pptpd/include/events.h
index 2f4c4e5..f0785be 100644
--- a/accel-pptpd/include/events.h
+++ b/accel-pptpd/include/events.h
@@ -1,6 +1,8 @@
#ifndef __EVENTS_H
#define __EVENTS_H
+#include <stdint.h>
+
#define EV_PPP_STARTING 1
#define EV_PPP_STARTED 2
#define EV_PPP_FINISHING 3
diff --git a/accel-pptpd/include/if_pppox.h b/accel-pptpd/include/if_pppox.h
index da327a1..0532d18 100644
--- a/accel-pptpd/include/if_pppox.h
+++ b/accel-pptpd/include/if_pppox.h
@@ -20,11 +20,11 @@
#include <asm/types.h>
#include <asm/byteorder.h>
#include <linux/version.h>
+#include <linux/if.h>
+#include <linux/if_ether.h>
#ifdef __KERNEL__
#include <linux/in.h>
-#include <linux/if_ether.h>
-#include <linux/if.h>
#include <linux/netdevice.h>
#include <linux/ppp_channel.h>
#endif /* __KERNEL__ */
@@ -37,7 +37,13 @@
#define PF_PPPOX AF_PPPOX
#endif /* !(AF_PPPOX) */
-struct pptp_addr{
+struct pppoe_addr {
+ __be16 sid;
+ unsigned char remote[ETH_ALEN];
+ char dev[IFNAMSIZ];
+};
+
+struct pptp_addr {
__u16 call_id;
struct in_addr sin_addr;
};
@@ -57,6 +63,7 @@ struct sockaddr_pppox {
sa_family_t sa_family; /* address family, AF_PPPOX */
unsigned int sa_protocol; /* protocol identifier */
union{
+ struct pppoe_addr pppoe;
struct pptp_addr pptp;
}sa_addr;
}__attribute__ ((packed));
diff --git a/accel-pptpd/ppp/ppp.c b/accel-pptpd/ppp/ppp.c
index 3e51ecb..24795b1 100644
--- a/accel-pptpd/ppp/ppp.c
+++ b/accel-pptpd/ppp/ppp.c
@@ -80,7 +80,7 @@ int __export establish_ppp(struct ppp_t *ppp)
{
/* Open an instance of /dev/ppp and connect the channel to it */
if (ioctl(ppp->fd, PPPIOCGCHAN, &ppp->chan_idx) == -1) {
- log_ppp_error("Couldn't get channel number\n");
+ log_ppp_error("ioctl(PPPIOCGCHAN): %s\n", strerror(errno));
return -1;
}
diff --git a/accel-pptpd/ppp/ppp_ccp.c b/accel-pptpd/ppp/ppp_ccp.c
index ae9e637..163881b 100644
--- a/accel-pptpd/ppp/ppp_ccp.c
+++ b/accel-pptpd/ppp/ppp_ccp.c
@@ -153,6 +153,8 @@ void ccp_layer_finish(struct ppp_layer_data_t *ld)
ccp_set_flags(ccp->ppp->unit_fd, 0, 0);
ccp->fsm.fsm_state = FSM_Closed;
+
+ log_ppp_debug("ccp_layer_finished\n");
ppp_layer_finished(ccp->ppp, &ccp->ld);
}
diff --git a/accel-pptpd/ppp/ppp_fsm.c b/accel-pptpd/ppp/ppp_fsm.c
index 4769dc8..3478d25 100644
--- a/accel-pptpd/ppp/ppp_fsm.c
+++ b/accel-pptpd/ppp/ppp_fsm.c
@@ -399,7 +399,7 @@ void ppp_fsm_recv_term_req(struct ppp_fsm_t *layer)
layer->fsm_state=FSM_Req_Sent;
break;
default:
- layer->send_term_req(layer);
+ layer->send_term_ack(layer);
break;
}
}
@@ -487,8 +487,10 @@ static void init_req_counter(struct ppp_fsm_t *layer,int timeout)
}
static void zero_req_counter(struct ppp_fsm_t *layer)
{
- layer->restart_timer.expire_tv.tv_sec=0;
layer->restart_counter=0;
+
+ if (!layer->restart_timer.tpd)
+ triton_timer_add(layer->ppp->ctrl->ctx, &layer->restart_timer, 0);
}
static void restart_timer_func(struct triton_timer_t *t)
diff --git a/accel-pptpd/ppp/ppp_ipcp.c b/accel-pptpd/ppp/ppp_ipcp.c
index c46b1bd..90e2b9c 100644
--- a/accel-pptpd/ppp/ppp_ipcp.c
+++ b/accel-pptpd/ppp/ppp_ipcp.c
@@ -116,6 +116,8 @@ void ipcp_layer_finish(struct ppp_layer_data_t *ld)
log_ppp_debug("ipcp_layer_finish\n");
ipcp->fsm.fsm_state = FSM_Closed;
+
+ log_ppp_debug("ipcp_layer_finished\n");
ppp_layer_finished(ipcp->ppp, &ipcp->ld);
}
diff --git a/rfc/rfc2516.txt b/rfc/rfc2516.txt
new file mode 100644
index 0000000..5397c86
--- /dev/null
+++ b/rfc/rfc2516.txt
@@ -0,0 +1,955 @@
+
+
+
+
+
+
+Network Working Group L. Mamakos
+Request for Comments: 2516 K. Lidl
+Category: Informational J. Evarts
+ UUNET Technologies, Inc.
+ D. Carrel
+ D. Simone
+ RedBack Networks, Inc.
+ R. Wheeler
+ RouterWare, Inc.
+ February 1999
+
+
+ A Method for Transmitting PPP Over Ethernet (PPPoE)
+
+Status of this Memo
+
+ This memo provides information for the Internet community. It does
+ not specify an Internet standard of any kind. Distribution of this
+ memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+Abstract
+
+ The Point-to-Point Protocol (PPP) [1] provides a standard method for
+ transporting multi-protocol datagrams over point-to-point links.
+
+ This document describes how to build PPP sessions and encapsulate PPP
+ packets over Ethernet.
+
+Applicability
+
+ This specification is intended to provide the facilities which are
+ defined for PPP, such as the Link Control Protocol, Network-layer
+ Control Protocols, authentication, and more. These capabilities
+ require a point-to-point relationship between the peers, and are not
+ designed for the multi-point relationships which are available in
+ Ethernet and other multi-access environments.
+
+ This specification can be used by multiple hosts on a shared,
+ Ethernet to open PPP sessions to multiple destinations via one or
+ more bridging modems. It is intended to be used with broadband
+ remote access technologies that provide a bridged Ethernet topology,
+ when access providers wish to maintain the session abstraction
+ associated with PPP.
+
+
+
+
+Mamakos, et. al. Informational [Page 1]
+
+RFC 2516 Transmitting PPP Over Ethernet February 1999
+
+
+ This document describes the PPP Over Ethernet encapsulation that is
+ being deployed by RedBack Networks, RouterWare, UUNET and others.
+
+1. Introduction
+
+ Modern access technologies are faced with several conflicting goals.
+ It is desirable to connect multiple hosts at a remote site through
+ the same customer premise access device. It is also a goal to
+ provide access control and billing functionality in a manner similar
+ to dial-up services using PPP. In many access technologies, the most
+ cost effective method to attach multiple hosts to the customer
+ premise access device, is via Ethernet. In addition, it is desirable
+ to keep the cost of this device as low as possible while requiring
+ little or no configuration.
+
+ PPP over Ethernet (PPPoE) provides the ability to connect a network
+ of hosts over a simple bridging access device to a remote Access
+ Concentrator. With this model, each host utilizes it's own PPP stack
+ and the user is presented with a familiar user interface. Access
+ control, billing and type of service can be done on a per-user,
+ rather than a per-site, basis.
+
+ To provide a point-to-point connection over Ethernet, each PPP
+ session must learn the Ethernet address of the remote peer, as well
+ as establish a unique session identifier. PPPoE includes a discovery
+ protocol that provides this.
+
+2. Conventions
+
+ The keywords MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD,
+ SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL, when they appear in this
+ document, are to be interpreted as described in [2].
+
+3. Protocol Overview
+
+ PPPoE has two distinct stages. There is a Discovery stage and a PPP
+ Session stage. When a Host wishes to initiate a PPPoE session, it
+ must first perform Discovery to identify the Ethernet MAC address of
+ the peer and establish a PPPoE SESSION_ID. While PPP defines a
+ peer-to-peer relationship, Discovery is inherently a client-server
+ relationship. In the Discovery process, a Host (the client)
+ discovers an Access Concentrator (the server). Based on the network
+ topology, there may be more than one Access Concentrator that the
+ Host can communicate with. The Discovery stage allows the Host to
+ discover all Access Concentrators and then select one. When
+ Discovery completes successfully, both the Host and the selected
+ Access Concentrator have the information they will use to build their
+ point-to-point connection over Ethernet.
+
+
+
+Mamakos, et. al. Informational [Page 2]
+
+RFC 2516 Transmitting PPP Over Ethernet February 1999
+
+
+ The Discovery stage remains stateless until a PPP session is
+ established. Once a PPP session is established, both the Host and
+ the Access Concentrator MUST allocate the resources for a PPP virtual
+ interface.
+
+4. Payloads
+
+ The following packet formats are defined here. The payload contents
+ will be defined in the Discovery and PPP sections.
+
+ An Ethernet frame is as follows:
+
+ 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | DESTINATION_ADDR |
+ | (6 octets) |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | SOURCE_ADDR |
+ | (6 octets) |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ETHER_TYPE (2 octets) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ~ ~
+ ~ payload ~
+ ~ ~
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | CHECKSUM |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ The DESTINATION_ADDR field contains either a unicast Ethernet
+ destination address, or the Ethernet broadcast address (0xffffffff).
+ For Discovery packets, the value is either a unicast or broadcast
+ address as defined in the Discovery section. For PPP session
+ traffic, this field MUST contain the peer's unicast address as
+ determined from the Discovery stage.
+
+ The SOURCE_ADDR field MUST contains the Ethernet MAC address of the
+ source device.
+
+ The ETHER_TYPE is set to either 0x8863 (Discovery Stage) or 0x8864
+ (PPP Session Stage).
+
+
+
+
+
+
+
+Mamakos, et. al. Informational [Page 3]
+
+RFC 2516 Transmitting PPP Over Ethernet February 1999
+
+
+ The Ethernet payload for PPPoE is as follows:
+
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | VER | TYPE | CODE | SESSION_ID |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | LENGTH | payload ~
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ The VER field is four bits and MUST be set to 0x1 for this version of
+ the PPPoE specification.
+
+ The TYPE field is four bits and MUST be set to 0x1 for this version
+ of the PPPoE specification.
+
+ The CODE field is eight bits and is defined below for the Discovery
+ and PPP Session stages.
+
+ The SESSION_ID field is sixteen bits. It is an unsigned value in
+ network byte order. It's value is defined below for Discovery
+ packets. The value is fixed for a given PPP session and, in fact,
+ defines a PPP session along with the Ethernet SOURCE_ADDR and
+ DESTINATION_ADDR. A value of 0xffff is reserved for future use and
+ MUST NOT be used
+
+ The LENGTH field is sixteen bits. The value, in network byte order,
+ indicates the length of the PPPoE payload. It does not include the
+ length of the Ethernet or PPPoE headers.
+
+5. Discovery Stage
+
+ There are four steps to the Discovery stage. When it completes, both
+ peers know the PPPoE SESSION_ID and the peer's Ethernet address,
+ which together define the PPPoE session uniquely. The steps consist
+ of the Host broadcasting an Initiation packet, one or more Access
+ Concentrators sending Offer packets, the Host sending a unicast
+ Session Request packet and the selected Access Concentrator sending a
+ Confirmation packet. When the Host receives the Confirmation packet,
+ it may proceed to the PPP Session Stage. When the Access
+ Concentrator sends the Confirmation packet, it may proceed to the PPP
+ Session Stage.
+
+ All Discovery Ethernet frames have the ETHER_TYPE field set to the
+ value 0x8863.
+
+
+
+
+
+
+Mamakos, et. al. Informational [Page 4]
+
+RFC 2516 Transmitting PPP Over Ethernet February 1999
+
+
+ The PPPoE payload contains zero or more TAGs. A TAG is a TLV (type-
+ length-value) construct and is defined as follows:
+
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | TAG_TYPE | TAG_LENGTH |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | TAG_VALUE ... ~
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ TAG_TYPE is a sixteen bit field in network byte order. Appendix A
+ contains a list of all TAG_TYPEs and their TAG_VALUEs.
+
+ TAG_LENGTH is a sixteen bit field. It is an unsigned number in
+ network byte order, indicating the length in octets of the TAG_VALUE.
+
+ If a discovery packet is received with a TAG of unknown TAG_TYPE, the
+ TAG MUST be ignored unless otherwise specified in this document.
+ This provides for backwards compatibility if/when new TAGs are added.
+ If new mandatory TAGs are added, the version number will be
+ incremented.
+
+ Some example Discovery packets are shown in Appendix B.
+
+5.1 The PPPoE Active Discovery Initiation (PADI) packet
+
+ The Host sends the PADI packet with the DESTINATION_ADDR set to the
+ broadcast address. The CODE field is set to 0x09 and the SESSION_ID
+ MUST be set to 0x0000.
+
+ The PADI packet MUST contain exactly one TAG of TAG_TYPE Service-
+ Name, indicating the service the Host is requesting, and any number
+ of other TAG types. An entire PADI packet (including the PPPoE
+ header) MUST NOT exceed 1484 octets so as to leave sufficient room
+ for a relay agent to add a Relay-Session-Id TAG.
+
+5.2 The PPPoE Active Discovery Offer (PADO) packet
+
+ When the Access Concentrator receives a PADI that it can serve, it
+ replies by sending a PADO packet. The DESTINATION_ADDR is the
+ unicast address of the Host that sent the PADI. The CODE field is
+ set to 0x07 and the SESSION_ID MUST be set to 0x0000.
+
+
+
+
+
+
+
+
+Mamakos, et. al. Informational [Page 5]
+
+RFC 2516 Transmitting PPP Over Ethernet February 1999
+
+
+ The PADO packet MUST contain one AC-Name TAG containing the Access
+ Concentrator's name, a Service-Name TAG identical to the one in the
+ PADI, and any number of other Service-Name TAGs indicating other
+ services that the Access Concentrator offers. If the Access
+ Concentrator can not serve the PADI it MUST NOT respond with a PADO.
+
+5.3 The PPPoE Active Discovery Request (PADR) packet
+
+ Since the PADI was broadcast, the Host may receive more than one
+ PADO. The Host looks through the PADO packets it receives and
+ chooses one. The choice can be based on the AC-Name or the Services
+ offered. The Host then sends one PADR packet to the Access
+ Concentrator that it has chosen. The DESTINATION_ADDR field is set
+ to the unicast Ethernet address of the Access Concentrator that sent
+ the PADO. The CODE field is set to 0x19 and the SESSION_ID MUST be
+ set to 0x0000.
+
+ The PADR packet MUST contain exactly one TAG of TAG_TYPE Service-
+ Name, indicating the service the Host is requesting, and any number
+ of other TAG types.
+
+5.4 The PPPoE Active Discovery Session-confirmation (PADS) packet
+
+ When the Access Concentrator receives a PADR packet, it prepares to
+ begin a PPP session. It generates a unique SESSION_ID for the PPPoE
+ session and replies to the Host with a PADS packet. The
+ DESTINATION_ADDR field is the unicast Ethernet address of the Host
+ that sent the PADR. The CODE field is set to 0x65 and the SESSION_ID
+ MUST be set to the unique value generated for this PPPoE session.
+
+ The PADS packet contains exactly one TAG of TAG_TYPE Service-Name,
+ indicating the service under which Access Concentrator has accepted
+ the PPPoE session, and any number of other TAG types.
+
+ If the Access Concentrator does not like the Service-Name in the
+ PADR, then it MUST reply with a PADS containing a TAG of TAG_TYPE
+ Service-Name-Error (and any number of other TAG types). In this case
+ the SESSION_ID MUST be set to 0x0000.
+
+5.5 The PPPoE Active Discovery Terminate (PADT) packet
+
+ This packet may be sent anytime after a session is established to
+ indicate that a PPPoE session has been terminated. It may be sent by
+ either the Host or the Access Concentrator. The DESTINATION_ADDR
+ field is a unicast Ethernet address, the CODE field is set to 0xa7
+ and the SESSION_ID MUST be set to indicate which session is to be
+ terminated. No TAGs are required.
+
+
+
+
+Mamakos, et. al. Informational [Page 6]
+
+RFC 2516 Transmitting PPP Over Ethernet February 1999
+
+
+ When a PADT is received, no further PPP traffic is allowed to be sent
+ using that session. Even normal PPP termination packets MUST NOT be
+ sent after sending or receiving a PADT. A PPP peer SHOULD use the
+ PPP protocol itself to bring down a PPPoE session, but the PADT MAY
+ be used when PPP can not be used.
+
+6. PPP Session Stage
+
+ Once the PPPoE session begins, PPP data is sent as in any other PPP
+ encapsulation. All Ethernet packets are unicast. The ETHER_TYPE
+ field is set to 0x8864. The PPPoE CODE MUST be set to 0x00. The
+ SESSION_ID MUST NOT change for that PPPoE session and MUST be the
+ value assigned in the Discovery stage. The PPPoE payload contains a
+ PPP frame. The frame begins with the PPP Protocol-ID.
+
+ An example packet is shown in Appendix B.
+
+7. LCP Considerations
+
+ The Magic Number LCP configuration option is RECOMMENDED, and the
+ Protocol Field Compression (PFC) option is NOT RECOMMENDED. An
+ implementation MUST NOT request any of the following options, and
+ MUST reject a request for such an option:
+
+ Field Check Sequence (FCS) Alternatives,
+
+ Address-and-Control-Field-Compression (ACFC),
+
+ Asynchronous-Control-Character-Map (ACCM)
+
+ The Maximum-Receive-Unit (MRU) option MUST NOT be negotiated to a
+ larger size than 1492. Since Ethernet has a maximum payload size of
+ 1500 octets, the PPPoE header is 6 octets and the PPP Protocol ID is
+ 2 octets, the PPP MTU MUST NOT be greater than 1492.
+
+ It is RECOMMENDED that the Access Concentrator ocassionally send
+ Echo-Request packets to the Host to determine the state of the
+ session. Otherwise, if the Host terminates a session without sending
+ a Terminate-Request packet, the Access Concentrator will not be able
+ to determine that the session has gone away.
+
+ When LCP terminates, the Host and Access concentrator MUST stop using
+ that PPPoE session. If the Host wishes to start another PPP session,
+ it MUST return to the PPPoE Discovery stage.
+
+
+
+
+
+
+
+Mamakos, et. al. Informational [Page 7]
+
+RFC 2516 Transmitting PPP Over Ethernet February 1999
+
+
+8. Other Considerations
+
+ When a host does not receive a PADO packet within a specified amount
+ of time, it SHOULD resend it's PADI packet and double the waiting
+ period. This is repeated as many times as desired. If the Host is
+ waiting to receive a PADS packet, a similar timeout mechanism SHOULD
+ be used, with the Host re-sending the PADR. After a specified number
+ of retries, the Host SHOULD then resend a PADI packet.
+
+ The ETHER_TYPEs used in this document (0x8863 and 0x8864) have been
+ assigned by the IEEE for use by PPP Over Ethernet (PPPoE). Use of
+ these values and the PPPoE VER (version) field uniquely identify this
+ protocol.
+
+ UTF-8 [5] is used throughout this document instead of ASCII. UTF-8
+ supports the entire ASCII character set while allowing for
+ international character sets as well. See [5] for more details.
+
+9. Security Considerations
+
+ To help protect against Denial of Service (DOS) attacks, the Access
+ Concentrator can employ the AC-Cookie TAG. The Access Concentrator
+ SHOULD be able to uniquely regenerate the TAG_VALUE based on the PADR
+ SOURCE_ADDR. Using this, the Access Concentrator can ensure that the
+ PADI SOURCE_ADDR is indeed reachable and can then limit concurrent
+ sessions for that address. What algorithm to use is not defined and
+ left as an implementation detail. An example is HMAC [3] over the
+ Host MAC address using a key known only to the Access > Concentrator.
+ While the AC-Cookie is useful against some DOS attacks, it can not
+ protect against all DOS attacks and an Access Concentrator MAY employ
+ other means to protect resources.
+
+ While the AC-Cookie is useful against some DOS attacks, it can not
+ protect against all DOS attacks and an Access Concentrator MAY employ
+ other means to protect resources.
+
+ Many Access Concentrators will not wish to offer information
+ regarding what services they offer to an unauthenticated entity. In
+ that case the Access Concentrator should employ one of two policies.
+ It SHOULD never refuse a request based on the Service-Name TAG, and
+ always return the TAG_VALUE that was sent to it. Or it SHOULD only
+ accept requests with a Service-Name TAG with a zero TAG_LENGTH
+ (indicating any service). The former solution is RECOMMENDED.
+
+10. Acknowledgments
+
+ This document is based on concepts discussed in several forums,
+ including the ADSL forum.
+
+
+
+Mamakos, et. al. Informational [Page 8]
+
+RFC 2516 Transmitting PPP Over Ethernet February 1999
+
+
+ Copious amounts of text have been stolen from RFC 1661, RFC 1662 and
+ RFC 2364.
+
+11. References
+
+ [1] Simpson, W., Editor, "The Point-to-Point Protocol (PPP)", STD 51,
+ RFC 1661, July 1994
+
+ [2] Bradner, S., "Key words for use in RFCs to Indicate Requirement
+ Levels", BCP 14, RFC 2119, March 1997.
+
+ [3] Krawczyk, H., Bellare, M. and R. Canetti, "HMAC: Keyed-Hashing
+ for Message Authentication", RFC 2104, February 1998.
+
+ [4] Reynolds, J. and J. Postel, "Assigned Numbers", STD 2, RFC 1700,
+ October 1994. See also: http://www.iana.org/numbers.html
+
+ [5] Yergeau, F., "UTF-8, a transformation format of ISO 10646", RFC
+ 2279, January 1998.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mamakos, et. al. Informational [Page 9]
+
+RFC 2516 Transmitting PPP Over Ethernet February 1999
+
+
+Appendix A
+
+ TAG_TYPES and TAG_VALUES
+
+ 0x0000 End-Of-List
+
+ This TAG indicates that there are no further TAGs in the list. The
+ TAG_LENGTH of this TAG MUST always be zero. Use of this TAG is
+ not required, but remains for backwards compatibility.
+
+ 0x0101 Service-Name
+
+ This TAG indicates that a service name follows. The TAG_VALUE is
+ an UTF-8 string that is NOT NULL terminated. When the TAG_LENGTH
+ is zero this TAG is used to indicate that any service is
+ acceptable. Examples of the use of the Service-Name TAG are to
+ indicate an ISP name or a class or quality of service.
+
+ 0x0102 AC-Name
+
+ This TAG indicates that a string follows which uniquely identifies
+ this particular Access Concentrator unit from all others. It may
+ be a combination of trademark, model, and serial id information,
+ or simply an UTF-8 rendition of the MAC address of the box. It is
+ not NULL terminated.
+
+ 0x0103 Host-Uniq
+
+ This TAG is used by a Host to uniquely associate an Access
+ Concentrator response (PADO or PADS) to a particular Host request
+ (PADI or PADR). The TAG_VALUE is binary data of any value and
+ length that the Host chooses. It is not interpreted by the Access
+ Concentrator. The Host MAY include a Host-Uniq TAG in a PADI or
+ PADR. If the Access Concentrator receives this TAG, it MUST
+ include the TAG unmodified in the associated PADO or PADS
+ response.
+
+ 0x0104 AC-Cookie
+
+ This TAG is used by the Access Concentrator to aid in protecting
+ against denial of service attacks (see the Security Considerations
+ section for an explanation of how this works). The Access
+ Concentrator MAY include this TAG in a PADO packet. If a Host
+ receives this TAG, it MUST return the TAG unmodified in the
+ following PADR. The TAG_VALUE is binary data of any value and
+ length and is not interpreted by the Host.
+
+
+
+
+
+Mamakos, et. al. Informational [Page 10]
+
+RFC 2516 Transmitting PPP Over Ethernet February 1999
+
+
+ 0x0105 Vendor-Specific
+
+ This TAG is used to pass vendor proprietary information. The
+ first four octets of the TAG_VALUE contain the vendor id and the
+ remainder is unspecified. The high-order octet of the vendor id
+ is 0 and the low-order 3 octets are the SMI Network Management
+ Private Enterprise Code of the Vendor in network byte order, as
+ defined in the Assigned Numbers RFC [4].
+
+ Use of this TAG is NOT RECOMMENDED. To ensure inter-operability,
+ an implementation MAY silently ignore a Vendor-Specific TAG.
+
+ 0x0110 Relay-Session-Id
+
+ This TAG MAY be added to any discovery packet by an intermediate
+ agent that is relaying traffic. The TAG_VALUE is opaque to both
+ the Host and the Access Concentrator. If either the Host or
+ Access Concentrator receives this TAG they MUST include it
+ unmodified in any discovery packet they send as a response. All
+ PADI packets MUST guarantee sufficient room for the addition of a
+ Relay-Session-Id TAG with a TAG_VALUE length of 12 octets.
+
+ A Relay-Session-Id TAG MUST NOT be added if the discovery packet
+ already contains one. In that case the intermediate agent SHOULD
+ use the existing Relay-Session-Id TAG. If it can not use the
+ existing TAG or there is insufficient room to add a Relay-
+ Session-Id TAG, then it SHOULD return a Generic-Error TAG to the
+ sender.
+
+ 0x0201 Service-Name-Error
+
+ This TAG (typically with a zero-length data section) indicates
+ that for one reason or another, the requested Service-Name request
+ could not be honored.
+
+ If there is data, and the first octet of the data is nonzero, then
+ it MUST be a printable UTF-8 string which explains why the request
+ was denied. This string MAY NOT be NULL terminated.
+
+ 0x0202 AC-System-Error
+
+ This TAG indicates that the Access Concentrator experienced some
+ error in performing the Host request. (For example insufficient
+ resources to create a virtual circuit.) It MAY be included in
+ PADS packets.
+
+
+
+
+
+
+Mamakos, et. al. Informational [Page 11]
+
+RFC 2516 Transmitting PPP Over Ethernet February 1999
+
+
+ If there is data, and the first octet of the data is nonzero, then
+ it MUST be a printable UTF-8 string which explains the nature of
+ the error. This string MAY NOT be NULL terminated.
+
+ 0x0203 Generic-Error
+
+ This TAG indicates an error. It can be added to PADO, PADR or
+ PADS packets when an unrecoverable error occurs and no other error
+ TAG is appropriate. If there is data then it MUST be an UTF-8
+ string which explains the nature of the error. This string MUST
+ NOT be NULL terminated.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mamakos, et. al. Informational [Page 12]
+
+RFC 2516 Transmitting PPP Over Ethernet February 1999
+
+
+Appendix B
+
+ The following are some example packets:
+
+ A PADI packet:
+
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 0xffffffff |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 0xffff | Host_mac_addr |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Host_mac_addr (cont) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ETHER_TYPE = 0x8863 | v = 1 | t = 1 | CODE = 0x09 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | SESSION_ID = 0x0000 | LENGTH = 0x0004 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | TAG_TYPE = 0x0101 | TAG_LENGTH = 0x0000 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mamakos, et. al. Informational [Page 13]
+
+RFC 2516 Transmitting PPP Over Ethernet February 1999
+
+
+ A PADO packet:
+
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Host_mac_addr |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Host_mac_addr (cont) | Access_Concentrator_mac_addr |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Access_Concentrator_mac_addr (cont) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ETHER_TYPE = 0x8863 | v = 1 | t = 1 | CODE = 0x07 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | SESSION_ID = 0x0000 | LENGTH = 0x0020 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | TAG_TYPE = 0x0101 | TAG_LENGTH = 0x0000 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | TAG_TYPE = 0x0102 | TAG_LENGTH = 0x0018 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 0x47 | 0x6f | 0x20 | 0x52 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 0x65 | 0x64 | 0x42 | 0x61 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 0x63 | 0x6b | 0x20 | 0x2d |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 0x20 | 0x65 | 0x73 | 0x68 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 0x73 | 0x68 | 0x65 | 0x73 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 0x68 | 0x6f | 0x6f | 0x74 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mamakos, et. al. Informational [Page 14]
+
+RFC 2516 Transmitting PPP Over Ethernet February 1999
+
+
+ A PPP LCP packet: The PPP protocol value is shown (0xc021) but the
+ PPP payload is left to the reader. This is a packet from the Host to
+ the Access Concentrator.
+
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Access_Concentrator_mac_addr |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |Access_Concentrator_mac_addr(c)| Host_mac_addr |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Host_mac_addr (cont) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ETHER_TYPE = 0x8864 | v = 1 | t = 1 | CODE = 0x00 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | SESSION_ID = 0x1234 | LENGTH = 0x???? |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | PPP PROTOCOL = 0xc021 | PPP payload ~
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+Authors' Addresses
+
+ Louis Mamakos
+ UUNET Technologies, Inc.
+ 3060 Williams Drive
+ Fairfax, VA 22031-4648
+ United States of America
+
+ EMail: louie@uu.net
+
+
+ Kurt Lidl
+ UUNET Technologies, Inc.
+ 3060 Williams Drive
+ Fairfax, VA 22031-4648
+ United States of America
+
+ EMail: lidl@uu.net
+
+
+ Jeff Evarts
+ UUNET Technologies, Inc.
+ 3060 Williams Drive
+ Fairfax, VA 22031-4648
+ United States of America
+
+ EMail: jde@uu.net
+
+
+
+
+Mamakos, et. al. Informational [Page 15]
+
+RFC 2516 Transmitting PPP Over Ethernet February 1999
+
+
+ David Carrel
+ RedBack Networks, Inc.
+ 1389 Moffett Park Drive
+ Sunnyvale, CA 94089-1134
+ United States of America
+
+ EMail: carrel@RedBack.net
+
+
+ Dan Simone
+ RedBack Networks, Inc.
+ 1389 Moffett Park Drive
+ Sunnyvale, CA 94089-1134
+ United States of America
+
+ EMail:dan@RedBack.net
+
+
+ Ross Wheeler
+ RouterWare, Inc.
+ 3961 MacArthur Blvd., Suite 212
+ Newport Beach, CA 92660
+ United States of America
+
+ EMail: ross@routerware.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mamakos, et. al. Informational [Page 16]
+
+RFC 2516 Transmitting PPP Over Ethernet February 1999
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mamakos, et. al. Informational [Page 17]
+