summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Wright <jason@cvs.openbsd.org>2000-06-18 07:30:42 +0000
committerJason Wright <jason@cvs.openbsd.org>2000-06-18 07:30:42 +0000
commit2150d33fb6cf1dfe1016cbf7782271645f323685 (patch)
treea63b5f9c629d99e6f6e3e99b7e00fb61855ed3c2
parenta9a8db41f99fc2b2bd057e21ca6bec6059a826af (diff)
import my pppoe code
-rw-r--r--usr.sbin/pppoe/Makefile7
-rw-r--r--usr.sbin/pppoe/client.c566
-rw-r--r--usr.sbin/pppoe/common.c293
-rw-r--r--usr.sbin/pppoe/debug.c202
-rw-r--r--usr.sbin/pppoe/pppoe.8129
-rw-r--r--usr.sbin/pppoe/pppoe.c420
-rw-r--r--usr.sbin/pppoe/pppoe.h146
-rw-r--r--usr.sbin/pppoe/rfc2516.txt955
-rw-r--r--usr.sbin/pppoe/server.c478
-rw-r--r--usr.sbin/pppoe/session.c140
-rw-r--r--usr.sbin/pppoe/tag.c188
11 files changed, 3524 insertions, 0 deletions
diff --git a/usr.sbin/pppoe/Makefile b/usr.sbin/pppoe/Makefile
new file mode 100644
index 00000000000..600f58f625d
--- /dev/null
+++ b/usr.sbin/pppoe/Makefile
@@ -0,0 +1,7 @@
+
+PROG= pppoe
+MAN= pppoe.8
+SRCS= client.c common.c debug.c pppoe.c server.c session.c tag.c
+CFLAGS+= -Werror -Wall -Wstrict-prototypes -Wmissing-prototypes
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/pppoe/client.c b/usr.sbin/pppoe/client.c
new file mode 100644
index 00000000000..519c70b60df
--- /dev/null
+++ b/usr.sbin/pppoe/client.c
@@ -0,0 +1,566 @@
+/* $OpenBSD: client.c,v 1.1 2000/06/18 07:30:41 jason Exp $ */
+
+/*
+ * Copyright (c) 2000 Network Security Technologies, Inc. http://www.netsec.net
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Network Security
+ * Technologies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <net/bpf.h>
+#include <net/ppp_defs.h>
+#include <errno.h>
+#include <string.h>
+#include <err.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sysexits.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <signal.h>
+
+#include "pppoe.h"
+
+#define PPP_PROG "/usr/sbin/ppp"
+
+#define STATE_EXPECT_PADO 1
+#define STATE_EXPECT_PADS 2
+#define STATE_EXPECT_SESSION 3
+
+u_int32_t client_cookie = 0;
+u_int16_t client_sessionid = 0xffff;
+int pppfd = -1;
+int client_state = -1;
+u_int8_t etherremoteaddr[6], etherlocaladdr[6];
+
+static int getpackets __P((int, char *, char *, struct ether_addr *,
+ struct ether_addr *));
+static int send_padi __P((int, struct ether_addr *, u_int8_t *));
+static int send_padr __P((int, char *, struct ether_addr *,
+ struct ether_addr *, struct ether_header *, struct pppoe_header *,
+ struct tag_list *));
+static int recv_pado __P((int, char *, struct ether_addr *,
+ struct ether_addr *, struct ether_header *, struct pppoe_header *,
+ u_long, u_int8_t *));
+static int recv_pads __P((int, char *, char *, struct ether_addr *,
+ struct ether_addr *, struct ether_header *, struct pppoe_header *,
+ u_long, u_int8_t *));
+static int recv_padt __P((int, struct ether_addr *, struct ether_addr *,
+ struct ether_header *, struct pppoe_header *, u_long, u_int8_t *));
+
+void timer_handler __P((int));
+int timer_set __P((u_int));
+int timer_clr __P((void));
+int timer_hit __P((void));
+
+int
+client_mode(bfd, sysname, srvname, myea)
+ int bfd;
+ char *sysname, *srvname;
+ struct ether_addr *myea;
+{
+ struct ether_addr rmea;
+ fd_set fds;
+ int r = 0, max;
+
+ pppfd = -1;
+ client_sessionid = 0xffff;
+
+ r = send_padi(bfd, myea, srvname);
+ if (r <= 0)
+ return (r);
+
+ FD_ZERO(&fds);
+ for (;;) {
+ FD_SET(bfd, &fds);
+ max = bfd + 1;
+ if (pppfd >= 0) {
+ if (pppfd >= max)
+ max = pppfd + 1;
+ FD_SET(pppfd, &fds);
+ }
+
+ r = select(max, &fds, NULL, NULL, NULL);
+ if (r < 0) {
+ if (errno == EINTR) {
+ if (timer_hit())
+ timer_clr();
+ break;
+ }
+ break;
+ }
+ if (FD_ISSET(bfd, &fds)) {
+ r = getpackets(bfd, srvname, sysname, myea, &rmea);
+ if (r <= 0)
+ break;
+ }
+ if (pppfd >= 0 && FD_ISSET(pppfd, &fds)) {
+ r = ppp_to_bpf(bfd, pppfd, myea, &rmea,
+ client_sessionid);
+ if (r < 0)
+ break;
+ }
+ }
+
+ if (pppfd >= 0) {
+ send_padt(bfd, myea, &rmea, client_sessionid);
+ close(pppfd);
+ pppfd = -1;
+ }
+ return (r);
+}
+
+static int
+send_padi(fd, ea, srv)
+ int fd;
+ struct ether_addr *ea;
+ u_int8_t *srv;
+{
+ struct iovec iov[10];
+ struct pppoe_header ph = {
+ PPPOE_VERTYPE(1, 1),
+ PPPOE_CODE_PADI, 0, 0
+ };
+ struct pppoe_tag thost, tserv;
+ u_int16_t etype = htons(ETHERTYPE_PPPOEDISC);
+ int i = 0;
+
+ /* ether_header */
+ iov[0].iov_base = etherbroadcastaddr;
+ iov[0].iov_len = ETHER_ADDR_LEN;
+ iov[1].iov_base = ea;
+ iov[1].iov_len = ETHER_ADDR_LEN;
+ iov[2].iov_base = &etype;
+ iov[2].iov_len = sizeof(etype);
+
+ /* pppoe_header */
+ iov[3].iov_base = &ph;
+ iov[3].iov_len = sizeof(ph);
+
+ /* host-uniq tag */
+ client_cookie = cookie_bake();
+ thost.type = htons(PPPOE_TAG_HOST_UNIQ);
+ thost.len = htons(sizeof(client_cookie));
+ ph.len += sizeof(thost.type)+sizeof(thost.len)+sizeof(client_cookie);
+ iov[4].iov_base = &thost;
+ iov[4].iov_len = sizeof(thost.len) + sizeof(thost.type) ;
+ iov[5].iov_base = &client_cookie;
+ iov[5].iov_len = sizeof(client_cookie);
+
+ /* service-name tag */
+ tserv.type = htons(PPPOE_TAG_SERVICE_NAME);
+ tserv.len = (srv == NULL) ? 0 : strlen(srv);
+ tserv.val = srv;
+ ph.len += tserv.len + sizeof(tserv.type) + sizeof(tserv.len);
+ iov[6].iov_base = &tserv;
+ iov[6].iov_len = sizeof(tserv.len) + sizeof(tserv.type);
+ i = 7;
+ if (tserv.len) {
+ iov[7].iov_base = tserv.val;
+ iov[7].iov_len = tserv.len;
+ i = 8;
+ }
+ tserv.len = htons(tserv.len);
+
+ ph.len = htons(ph.len);
+
+ client_state = STATE_EXPECT_PADO;
+ timer_set(10);
+ return (writev(fd, iov, i));
+}
+
+static int
+send_padr(bfd, srv, myea, rmea, eh, ph, tl)
+ int bfd;
+ char *srv;
+ struct ether_addr *myea, *rmea;
+ struct ether_header *eh;
+ struct pppoe_header *ph;
+ struct tag_list *tl;
+{
+ struct iovec iov[12];
+ u_int16_t etype = htons(ETHERTYPE_PPPOEDISC);
+ struct pppoe_tag hutag, svtag;
+ struct tag_node *n;
+ int idx = 0, slen;
+
+ timer_set(5);
+ client_state = STATE_EXPECT_PADS;
+
+ iov[idx].iov_base = rmea;
+ iov[idx++].iov_len = ETHER_ADDR_LEN;
+ iov[idx].iov_base = myea;
+ iov[idx++].iov_len = ETHER_ADDR_LEN;
+ iov[idx].iov_base = &etype;
+ iov[idx++].iov_len = sizeof(etype);
+
+ ph->vertype = PPPOE_VERTYPE(1, 1);
+ ph->code = PPPOE_CODE_PADR;
+ ph->len = 0;
+ ph->sessionid = 0;
+ iov[idx].iov_base = ph;
+ iov[idx++].iov_len = sizeof(struct pppoe_header);
+
+ /* Host-Uniq */
+ hutag.type = htons(PPPOE_TAG_HOST_UNIQ);
+ hutag.len = htons(sizeof(client_cookie));
+ iov[idx].iov_base = &hutag;
+ iov[idx++].iov_len = sizeof(hutag.type) + sizeof(hutag.len);
+ ph->len += sizeof(hutag.type)+sizeof(hutag.len)+sizeof(client_cookie);
+ iov[idx].iov_base = &client_cookie;
+ iov[idx++].iov_len = sizeof(client_cookie);
+
+ /* Service-Name */
+ slen = (srv == NULL) ? 0 : strlen(srv);
+ svtag.type = htons(PPPOE_TAG_SERVICE_NAME);
+ svtag.len = htons(slen);
+ iov[idx].iov_base = &svtag;
+ iov[idx++].iov_len = sizeof(hutag.type) + sizeof(hutag.len);
+ ph->len += slen + sizeof(hutag.type) + sizeof(hutag.len);
+ if (slen) {
+ iov[idx].iov_base = srv;
+ iov[idx++].iov_len = slen;
+ }
+
+ n = tag_lookup(tl, PPPOE_TAG_RELAY_SESSION, 0);
+ if (n != NULL) {
+ iov[idx].iov_base = &n->type;
+ iov[idx++].iov_len = sizeof(n->type) + sizeof(n->len);
+ if (n->len) {
+ iov[idx].iov_base = &n->val;
+ iov[idx++].iov_len = n->len;
+ }
+ ph->len += sizeof(n->type) + sizeof(n->len) + n->len;
+ }
+
+ n = tag_lookup(tl, PPPOE_TAG_AC_COOKIE, 0);
+ if (n != NULL) {
+ iov[idx].iov_base = &n->type;
+ iov[idx++].iov_len = sizeof(n->type) + sizeof(n->len);
+ if (n->len) {
+ iov[idx].iov_base = n->val;
+ iov[idx++].iov_len = n->len;
+ }
+ ph->len += sizeof(n->type) + sizeof(n->len) + n->len;
+ }
+
+ ph->len = htons(ph->len);
+ tag_hton(tl);
+
+ return (writev(bfd, iov, idx));
+}
+
+static int
+getpackets(bfd, srv, sysname, myea, rmea)
+ int bfd;
+ char *srv, *sysname;
+ struct ether_addr *myea, *rmea;
+{
+ static u_int8_t *pktbuf;
+ u_int8_t *mpkt, *pkt, *epkt;
+ struct ether_header eh;
+ struct pppoe_header ph;
+ struct bpf_hdr *bh;
+ int rlen, r;
+ u_long len;
+
+ if (pktbuf == NULL) {
+ pktbuf = (u_int8_t *)malloc(PPPOE_BPF_BUFSIZ);
+ if (pktbuf == NULL)
+ return (-1);
+ }
+
+ rlen = read(bfd, pktbuf, PPPOE_BPF_BUFSIZ);
+ if (rlen < 0) {
+ if (errno == EINTR)
+ return (0);
+ return (-1);
+ }
+
+ pkt = pktbuf;
+ epkt = pkt + rlen;
+ while (pkt < epkt) {
+ bh = (struct bpf_hdr *)pkt;
+ len = bh->bh_caplen;
+ mpkt = pkt + bh->bh_hdrlen;
+
+ debug_packet(mpkt, len);
+
+ /* Pull out ethernet header */
+ if (len < sizeof(struct ether_header))
+ goto next;
+ bcopy(mpkt, &eh, sizeof(struct ether_header));
+ eh.ether_type = ntohs(eh.ether_type);
+ len -= sizeof(struct ether_header);
+ mpkt += sizeof(struct ether_header);
+
+ /* Pull out pppoe header */
+ if (len < sizeof(struct pppoe_header))
+ goto next;
+ bcopy(mpkt, &ph, sizeof(struct pppoe_header));
+ len -= sizeof(struct pppoe_header);
+ mpkt += sizeof(struct pppoe_header);
+ ph.len = ntohs(ph.len);
+ ph.sessionid = ntohs(ph.sessionid);
+
+ if (PPPOE_VER(ph.vertype) != 1 ||
+ PPPOE_TYPE(ph.vertype) != 1)
+ goto next;
+
+ if (len > ph.len)
+ len = ph.len;
+
+ if (eh.ether_type == ETHERTYPE_PPPOEDISC) {
+ /* Discovery Stage */
+ switch (ph.code) {
+ case PPPOE_CODE_PADO:
+ r = recv_pado(bfd, srv, myea, rmea, &eh,
+ &ph, len, mpkt);
+ break;
+ case PPPOE_CODE_PADS:
+ r = recv_pads(bfd, srv, sysname, myea, rmea,
+ &eh, &ph, len, mpkt);
+ break;
+ case PPPOE_CODE_PADT:
+ r = recv_padt(bfd, myea, rmea, &eh, &ph,
+ len, mpkt);
+ break;
+ default:
+ recv_debug(bfd, myea, &eh, &ph, len, mpkt);
+ r = 0;
+ }
+ if (r < 0)
+ return (r);
+ }
+ else if (eh.ether_type == ETHERTYPE_PPPOE) {
+ if (client_state != STATE_EXPECT_SESSION)
+ goto next;
+ if (bcmp(rmea, &eh.ether_shost[0], ETHER_ADDR_LEN))
+ goto next;
+ if (pppfd <= 0)
+ goto next;
+ if (bpf_to_ppp(pppfd, len, mpkt) <= 0)
+ return (-1);
+ }
+next:
+ pkt += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
+ }
+ return (1);
+}
+
+
+static int
+recv_pado(bfd, srv, myea, rmea, eh, ph, len, pkt)
+ int bfd;
+ char *srv;
+ struct ether_addr *myea, *rmea;
+ struct ether_header *eh;
+ struct pppoe_header *ph;
+ u_long len;
+ u_int8_t *pkt;
+{
+ struct tag_list tl;
+ struct tag_node *n;
+ int r, slen;
+
+ if (timer_hit()) {
+ timer_clr();
+ return (0);
+ }
+
+ if (client_state != STATE_EXPECT_PADO)
+ return (0);
+
+ tag_init(&tl);
+ if (tag_pkt(&tl, len, pkt) < 0)
+ goto out;
+
+ if (ph->sessionid != 0)
+ goto out;
+
+ if (tag_lookup(&tl, PPPOE_TAG_AC_NAME, 0) == NULL)
+ goto out;
+
+ n = tag_lookup(&tl, PPPOE_TAG_HOST_UNIQ, 0);
+ if (n == NULL || n->len != sizeof(client_cookie))
+ goto out;
+ if (bcmp(n->val, &client_cookie, sizeof(client_cookie)))
+ goto out;
+
+ r = 0;
+ slen = (srv == NULL) ? 0 : strlen(srv);
+ while ((n = tag_lookup(&tl, PPPOE_TAG_SERVICE_NAME, r)) != NULL) {
+ if (slen == 0 || n->len == 0)
+ break;
+ if (n->len == slen && !strncmp(srv, n->val, slen))
+ break;
+ r++;
+ }
+
+ if (n == NULL)
+ goto out;
+
+ bcopy(&eh->ether_shost[0], rmea, ETHER_ADDR_LEN);
+
+ timer_clr();
+ r = send_padr(bfd, srv, myea, rmea, eh, ph, &tl);
+ tag_destroy(&tl);
+ return (r);
+
+out:
+ tag_destroy(&tl);
+ return (0);
+}
+
+static int
+recv_pads(bfd, srv, sysname, myea, rmea, eh, ph, len, pkt)
+ int bfd;
+ char *srv, *sysname;
+ struct ether_addr *myea, *rmea;
+ struct ether_header *eh;
+ struct pppoe_header *ph;
+ u_long len;
+ u_int8_t *pkt;
+{
+ struct tag_node *n;
+ struct tag_list tl;
+
+ if (timer_hit()) {
+ timer_clr();
+ return (0);
+ }
+
+ if (bcmp(rmea, &eh->ether_shost[0], ETHER_ADDR_LEN))
+ return (0);
+
+ if (client_state != STATE_EXPECT_PADS)
+ return (0);
+
+ tag_init(&tl);
+ if (tag_pkt(&tl, len, pkt) < 0)
+ goto out;
+
+ n = tag_lookup(&tl, PPPOE_TAG_HOST_UNIQ, 0);
+ if (n == NULL || n->len != sizeof(client_cookie))
+ goto out;
+ if (bcmp(n->val, &client_cookie, sizeof(client_cookie)))
+ goto out;
+
+ if (ph->sessionid == 0) {
+ timer_clr();
+ return (-1);
+ }
+
+ timer_clr();
+
+ pppfd = runppp(bfd, sysname);
+ if (pppfd < 0) {
+ send_padt(bfd, myea, rmea, ph->sessionid);
+ return (-1);
+ }
+
+ client_state = STATE_EXPECT_SESSION;
+ client_sessionid = ph->sessionid;
+
+out:
+ tag_destroy(&tl);
+ return (0);
+}
+
+static int
+recv_padt(bfd, myea, rmea, eh, ph, len, pkt)
+ int bfd;
+ struct ether_addr *myea, *rmea;
+ struct ether_header *eh;
+ struct pppoe_header *ph;
+ u_long len;
+ u_int8_t *pkt;
+{
+ if (bcmp(&eh->ether_shost[0], rmea, ETHER_ADDR_LEN))
+ return (0);
+
+ if (client_sessionid != 0xffff && ph->sessionid == client_sessionid)
+ return (-1);
+
+ return (0);
+}
+
+static volatile int timer_alarm;
+static struct sigaction timer_oact;
+
+void
+timer_handler(sig)
+ int sig;
+{
+ timer_alarm = 1;
+}
+
+int
+timer_set(sec)
+ u_int sec;
+{
+ struct sigaction act;
+
+ timer_alarm = 0;
+ if (sigemptyset(&act.sa_mask) < 0)
+ return (-1);
+ act.sa_flags = 0;
+ act.sa_handler = timer_handler;
+ if (sigaction(SIGALRM, &act, &timer_oact) < 0)
+ return (-1);
+ alarm(sec);
+ return (0);
+}
+
+int
+timer_clr(void)
+{
+ alarm(0);
+ if (sigaction(SIGALRM, &timer_oact, NULL) < 0)
+ return (-1);
+ timer_alarm = 0;
+ return (0);
+}
+
+int
+timer_hit(void)
+{
+ return (timer_alarm);
+}
diff --git a/usr.sbin/pppoe/common.c b/usr.sbin/pppoe/common.c
new file mode 100644
index 00000000000..e47537bbb0f
--- /dev/null
+++ b/usr.sbin/pppoe/common.c
@@ -0,0 +1,293 @@
+/* $OpenBSD: common.c,v 1.1 2000/06/18 07:30:41 jason Exp $ */
+
+/*
+ * Copyright (c) 2000 Network Security Technologies, Inc. http://www.netsec.net
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Network Security
+ * Technologies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/ppp_defs.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <net/bpf.h>
+#include <errno.h>
+#include <string.h>
+#include <err.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sysexits.h>
+#include <stdlib.h>
+#include <grp.h>
+#include <syslog.h>
+#include <md5.h>
+
+#include "pppoe.h"
+
+#define PPP_PROG "/usr/sbin/ppp"
+
+void debugv __P((char *, struct iovec *, int));
+
+int
+runppp(bpffd, sysname)
+ int bpffd;
+ char *sysname;
+{
+ int socks[2], fdm, fds, closeit;
+ pid_t pid;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) < 0)
+ return (-1);
+
+ fdm = socks[0];
+ fds = socks[1];
+
+ pid = fork();
+ if (pid < 0) {
+ close(fds);
+ close(fdm);
+ return (-1);
+ }
+
+ if (pid != 0) {
+ /* Parent */
+ close(fds);
+ return (fdm);
+ }
+
+ if (setsid() < 0)
+ _exit(99);
+
+ /* Child */
+ close(bpffd);
+ close(fdm);
+ closeit = 1;
+
+ if (fds == STDIN_FILENO)
+ closeit = 0;
+ else
+ dup2(fds, STDIN_FILENO);
+
+ if (fds == STDOUT_FILENO)
+ closeit = 0;
+ else
+ dup2(fds, STDOUT_FILENO);
+
+ if (fds == STDERR_FILENO)
+ closeit = 0;
+ else
+ dup2(fds, STDERR_FILENO);
+
+ if (closeit)
+ close(fds);
+
+ execlp(PPP_PROG, "ppp", "-direct", sysname, NULL);
+ perror("execlp");
+ syslog(LOG_INFO, "%s exec failed: %m", PPP_PROG);
+ _exit(-1);
+}
+
+int
+bpf_to_ppp(pppfd, len, pkt)
+ int pppfd;
+ u_long len;
+ u_int8_t *pkt;
+{
+ int r;
+ u_int8_t hdr[2] = { PPP_ALLSTATIONS, PPP_UI };
+ struct iovec iov[2];
+
+ iov[0].iov_base = hdr;
+ iov[0].iov_len = sizeof(hdr);
+ iov[1].iov_base = pkt;
+ iov[1].iov_len = len;
+
+ r = writev(pppfd, iov, 2);
+ if (r < 0) {
+ if (errno == EINTR || errno == EPIPE)
+ return (0);
+ return (-1);
+ }
+ return (1);
+}
+
+int
+ppp_to_bpf(bfd, pppfd, myea, rmea, id)
+ int bfd, pppfd;
+ struct ether_addr *myea, *rmea;
+ u_int16_t id;
+{
+ static u_int8_t *pktbuf = NULL;
+ struct pppoe_header ph;
+ struct iovec iov[5];
+ u_int16_t etype;
+ u_int8_t trash[2];
+ int r;
+
+ if (pktbuf == NULL) {
+ pktbuf = (u_int8_t *)malloc(PPPOE_MTU);
+ if (pktbuf == NULL)
+ return (-1);
+ }
+
+ iov[0].iov_base = trash;
+ iov[0].iov_len = 2;
+ iov[1].iov_base = pktbuf;
+ iov[1].iov_len = PPPOE_MTU;
+ r = readv(pppfd, iov, 2);
+ if (r <= 0)
+ return (-1);
+ r -= 2;
+
+ iov[0].iov_len = 2;
+ iov[1].iov_len = r;
+
+ ph.vertype = PPPOE_VERTYPE(1, 1);
+ ph.code = PPPOE_CODE_SESSION;
+ ph.len = htons(r);
+ ph.sessionid = htons(id);
+ etype = htons(ETHERTYPE_PPPOE);
+
+ iov[0].iov_base = rmea; iov[0].iov_len = ETHER_ADDR_LEN;
+ iov[1].iov_base = myea; iov[1].iov_len = ETHER_ADDR_LEN;
+ iov[2].iov_base = &etype; iov[2].iov_len = sizeof(etype);
+ iov[3].iov_base = &ph; iov[3].iov_len = sizeof(ph);
+ iov[4].iov_base = pktbuf; iov[4].iov_len = r;
+
+ return (writev(bfd, iov, 5));
+}
+
+void
+debugv(s, iov, cnt)
+ char *s;
+ struct iovec *iov;
+ int cnt;
+{
+ int i, j;
+ u_int8_t *p;
+
+ printf("%s", s);
+ for (i = 0; i < cnt; i++)
+ for (j = 0; j < iov[i].iov_len; j++) {
+ p = (u_int8_t *)iov[i].iov_base;
+ printf("%02x:", p[j]);
+ }
+ printf("\n\n");
+}
+
+void
+recv_debug(bpffd, ea, eh, ph, pktlen, pktbuf)
+ int bpffd;
+ struct ether_addr *ea;
+ struct ether_header *eh;
+ struct pppoe_header *ph;
+ u_long pktlen;
+ u_int8_t *pktbuf;
+{
+ struct tag_list tl;
+
+ printf("dst %02x:%02x:%02x:%02x:%02x:%02x, "
+ "src %02x:%02x:%02x:%02x:%02x:%02x, type %04x\n",
+ eh->ether_dhost[0], eh->ether_dhost[1], eh->ether_dhost[2],
+ eh->ether_dhost[3], eh->ether_dhost[4], eh->ether_dhost[5],
+ eh->ether_shost[0], eh->ether_shost[1], eh->ether_shost[2],
+ eh->ether_shost[3], eh->ether_shost[4], eh->ether_shost[5],
+ eh->ether_type);
+ printf("\tver %d, type %d, code %02x, id %04x, len %d\n",
+ PPPOE_VER(ph->vertype), PPPOE_TYPE(ph->vertype),
+ ph->code, ph->sessionid, ph->len);
+
+ tag_init(&tl);
+ if (tag_pkt(&tl, pktlen, pktbuf) < 0) {
+ printf("bad tag pkt\n");
+ goto out;
+ }
+
+ tag_show(&tl);
+out:
+ tag_destroy(&tl);
+}
+
+int
+send_padt(bpffd, src_ea, dst_ea, id)
+ int bpffd;
+ struct ether_addr *src_ea, *dst_ea;
+ u_int16_t id;
+{
+ struct iovec iov[4];
+ struct pppoe_header ph;
+ u_int16_t etype = htons(ETHERTYPE_PPPOEDISC);
+
+ iov[0].iov_base = dst_ea;
+ iov[0].iov_len = ETHER_ADDR_LEN;
+ iov[1].iov_base = src_ea;
+ iov[1].iov_len = ETHER_ADDR_LEN;
+ iov[2].iov_base = &etype;
+ iov[2].iov_len = sizeof(etype);
+ iov[3].iov_base = &ph;
+ iov[3].iov_len = sizeof(ph);
+
+ ph.vertype = PPPOE_VERTYPE(1, 1);
+ ph.code = PPPOE_CODE_PADT;
+ ph.len = 0;
+ ph.sessionid = htons(id);
+
+ return (writev(bpffd, iov, 4));
+}
+
+u_int32_t
+cookie_bake()
+{
+ MD5_CTX ctx;
+ char buf[40];
+ u_int32_t x, y;
+
+ x = arc4random();
+ MD5Init(&ctx);
+ MD5Update(&ctx, (unsigned char *)&x, sizeof(x));
+ MD5Final(buf, &ctx);
+ bcopy(buf, &y, sizeof(y));
+ x = x ^ y;
+ bcopy(buf + 4, &y, sizeof(y));
+ x = x ^ y;
+ bcopy(buf + 8, &y, sizeof(y));
+ x = x ^ y;
+ bcopy(buf + 12, &y, sizeof(y));
+ x = x ^ y;
+ return (x);
+}
diff --git a/usr.sbin/pppoe/debug.c b/usr.sbin/pppoe/debug.c
new file mode 100644
index 00000000000..068ead724ce
--- /dev/null
+++ b/usr.sbin/pppoe/debug.c
@@ -0,0 +1,202 @@
+/* $OpenBSD: debug.c,v 1.1 2000/06/18 07:30:41 jason Exp $ */
+
+/*
+ * Copyright (c) 2000 Network Security Technologies, Inc. http://www.netsec.net
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Network Security
+ * Technologies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/ppp_defs.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "pppoe.h"
+
+void
+debug_packet(u_int8_t *pkt, int len)
+{
+ struct ether_header eh;
+ struct pppoe_header ph;
+
+ if (option_verbose == 0)
+ return;
+
+ if (len < sizeof(eh)) {
+ printf("short packet (%d)\n", len);
+ return;
+ }
+ bcopy(pkt, &eh, sizeof(eh));
+ pkt += sizeof(eh);
+ len -= sizeof(eh);
+ eh.ether_type = ntohs(eh.ether_type);
+
+ if (eh.ether_type == ETHERTYPE_PPPOE && option_verbose < 2)
+ return;
+
+ printf("%s -> %s %04x[",
+ ether_ntoa((struct ether_addr *)eh.ether_shost),
+ ether_ntoa((struct ether_addr *)eh.ether_dhost),
+ eh.ether_type);
+ switch (eh.ether_type) {
+ case ETHERTYPE_PPPOEDISC:
+ printf("discovery]");
+ break;
+ case ETHERTYPE_PPPOE:
+ printf("session]");
+ break;
+ default:
+ printf("unknown]\n");
+ return;
+ }
+
+ if (len < sizeof(ph)) {
+ printf("short packet (%d)\n", len);
+ return;
+ }
+ bcopy(pkt, &ph, sizeof(ph));
+ pkt += sizeof(ph);
+ len -= sizeof(ph);
+ ph.sessionid = ntohs(ph.sessionid);
+ ph.len = ntohs(ph.len);
+
+ if (ph.len <= len)
+ len = ph.len;
+ else {
+ printf("missing (%d)\n", ph.len - len);
+ return;
+ }
+
+ printf(": version %d, type %d, ",
+ PPPOE_VER(ph.vertype), PPPOE_TYPE(ph.vertype));
+ switch (ph.code) {
+ case PPPOE_CODE_SESSION:
+ printf("session");
+ case PPPOE_CODE_PADO:
+ printf("PADO");
+ break;
+ case PPPOE_CODE_PADI:
+ printf("PADI");
+ break;
+ case PPPOE_CODE_PADR:
+ printf("PADR");
+ break;
+ case PPPOE_CODE_PADS:
+ printf("PADS");
+ break;
+ case PPPOE_CODE_PADT:
+ printf("PADT");
+ break;
+ default:
+ printf("unknown");
+ break;
+ }
+ printf(", len %d\n", len);
+
+ while (len > 0 && eh.ether_type == ETHERTYPE_PPPOEDISC) {
+ int i;
+ u_int16_t ttype, tlen;
+
+ if (len < sizeof(ttype)) {
+ printf("|\n");
+ return;
+ }
+ bcopy(pkt, &ttype, sizeof(ttype));
+ len -= sizeof(ttype);
+ pkt += sizeof(ttype);
+ ttype = ntohs(ttype);
+ printf("\ttag ");
+ switch (ttype) {
+ case PPPOE_TAG_END_OF_LIST:
+ printf("end-of-list");
+ break;
+ case PPPOE_TAG_SERVICE_NAME:
+ printf("service-name");
+ break;
+ case PPPOE_TAG_AC_NAME:
+ printf("ac-name");
+ break;
+ case PPPOE_TAG_HOST_UNIQ:
+ printf("host-uniq");
+ break;
+ case PPPOE_TAG_AC_COOKIE:
+ printf("ac-cookie");
+ break;
+ case PPPOE_TAG_VENDOR_SPEC:
+ printf("vendor-spec");
+ break;
+ case PPPOE_TAG_RELAY_SESSION:
+ printf("relay-session");
+ break;
+ case PPPOE_TAG_SERVICE_NAME_ERROR:
+ printf("service-name-error");
+ break;
+ case PPPOE_TAG_AC_SYSTEM_ERROR:
+ printf("ac-system-error");
+ break;
+ case PPPOE_TAG_GENERIC_ERROR:
+ printf("generic-error");
+ break;
+ default:
+ printf("unknown %04x", ttype);
+ break;
+ }
+
+ if (len < sizeof(tlen)) {
+ printf("|\n");
+ return;
+ }
+ bcopy(pkt, &tlen, sizeof(tlen));
+ len -= sizeof(tlen);
+ pkt += sizeof(tlen);
+ tlen = ntohs(tlen);
+ printf(", len %d", tlen);
+
+ if (len < tlen) {
+ printf("|\n");
+ return;
+ }
+ for (i = 0; i < tlen; i++) {
+ if (isprint(pkt[i]))
+ printf("%c", pkt[i]);
+ else
+ printf("\\%03o", pkt[i]);
+ }
+ len -= tlen;
+ }
+}
diff --git a/usr.sbin/pppoe/pppoe.8 b/usr.sbin/pppoe/pppoe.8
new file mode 100644
index 00000000000..43469b15ed3
--- /dev/null
+++ b/usr.sbin/pppoe/pppoe.8
@@ -0,0 +1,129 @@
+.\" $OpenBSD: pppoe.8,v 1.1 2000/06/18 07:30:41 jason Exp $
+.\"
+.\" Copyright (c) 2000 Network Security Technologies, Inc.
+.\" (http://www.netsec.net)
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Jason L. Wright
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\"
+.Dd February 8, 2000
+.Dt PPPOE 8
+.Os
+.Sh NAME
+.Nm pppoe
+.Nd PPP Over Ethernet translator
+.Sh SYNOPSIS
+.Nm pppoe
+.Op Ar -s
+.Op Ar -v
+.Op Ar -i interface
+.Op Ar -n service
+.Op Ar -p system
+.Sh DESCRIPTION
+The
+.Nm pppoe
+program can, with the help of
+.Xr ppp 8 ,
+act as a server or client for running PPP Over Ethernet.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl i Ar interface
+Specify the interface that
+.Nm
+is to use. If this option is not specified,
+.Nm
+will use the first Ethernet interface that is up and running.
+.It Fl n Ar service
+Use
+.Ar service
+as the service name when negotiating with the server. By default,
+the client will ask for any service, and expect the server to
+respond with the same.
+.It Fl p Ar system
+This argument is passed, uninterpreted, to
+.Xr ppp 8 .
+It can be used to specify the configuration data to be used for
+PPP Over Ethernet connections.
+.It Fl s
+If this option is specified,
+.Nm
+will run as a server. Otherwise,
+.Nm
+runs as a client.
+.It Fl v
+For each use of the flag, the verbosity of
+.Nm pppoe
+increases.
+.El
+.Sh CLIENT SETUP
+Configuring the client involves setting up the
+configuration file for
+.Xr ppp 8 .
+The following statements must be included in the file for
+the specified
+.Ar system
+(or
+``default''
+if no
+.Ar system
+is specified):
+.Bl -tag -width XXX -offset XXX
+.It set mtu 1492
+.It set mru 1492
+.It set speed sync
+.It disable acfcomp
+.It deny acfcomp
+.It disable protocomp
+.El
+.Pp
+Additionally, the authentication mechanism for the connection
+must be specified as well as any other parameters.
+.Sh SEE ALSO
+.Xr ppp 8
+.Sh HISTORY
+This implementation of
+.Nm pppoe
+first appeared in
+.Ox 2.8 .
+.Sh BUGS
+This is software runs completely in user mode. As such it will have much
+more overhead than a kernel implementation.
+.Pp
+The
+.Ar service
+is not currently used by the server code.
+.Sh AUTHOR
+The
+.Nm pppoe
+program was written by
+.An Jason L. Wright
+.Aq jason@thought.net
+of
+.An Network Security Technologies, Inc.
+.Aq http://www.netsec.net .
diff --git a/usr.sbin/pppoe/pppoe.c b/usr.sbin/pppoe/pppoe.c
new file mode 100644
index 00000000000..ab1e89a0efd
--- /dev/null
+++ b/usr.sbin/pppoe/pppoe.c
@@ -0,0 +1,420 @@
+/* $OpenBSD: pppoe.c,v 1.1 2000/06/18 07:30:41 jason Exp $ */
+
+/*
+ * Copyright (c) 2000 Network Security Technologies, Inc. http://www.netsec.net
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Network Security
+ * Technologies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <net/bpf.h>
+#include <errno.h>
+#include <string.h>
+#include <err.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sysexits.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#include "pppoe.h"
+
+int option_verbose = 0;
+u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+int main __P((int, char **));
+void usage __P((char *));
+int getifhwaddr __P((char *, char *, struct ether_addr *));
+int setupfilter __P((char *, struct ether_addr *, int));
+void child_handler __P((int));
+int signal_init __P((void));
+
+int
+main(int argc, char **argv) {
+ char *ifname = NULL, *sysname = NULL, *srvname = NULL;
+ char ifnambuf[IFNAMSIZ];
+ struct ether_addr ea;
+ int bpffd, smode = 0, c;
+
+ while ((c = getopt(argc, argv, "svi:n:p:")) != -1) {
+ switch (c) {
+ case 'i':
+ if (ifname != NULL) {
+ usage(argv[0]);
+ return (EX_USAGE);
+ }
+ ifname = optarg;
+ break;
+ case 'n':
+ if (srvname != NULL) {
+ usage(argv[0]);
+ return (EX_USAGE);
+ }
+ srvname = optarg;
+ break;
+ case 'p':
+ if (sysname != NULL) {
+ usage(argv[0]);
+ return (EX_USAGE);
+ }
+ sysname = optarg;
+ break;
+ case 's':
+ if (smode) {
+ usage(argv[0]);
+ return (EX_USAGE);
+ }
+ smode = 1;
+ break;
+ case 'v':
+ option_verbose++;
+ break;
+ default:
+ usage(argv[0]);
+ return (EX_USAGE);
+ }
+ }
+
+ argc -= optind;
+ if (argc != 0) {
+ usage(argv[0]);
+ return (EX_USAGE);
+ }
+
+ if (getifhwaddr(ifname, ifnambuf, &ea) < 0)
+ return (EX_IOERR);
+
+ bpffd = setupfilter(ifnambuf, &ea, smode);
+ if (bpffd < 0)
+ return (EX_IOERR);
+
+ signal_init();
+
+ if (smode)
+ server_mode(bpffd, sysname, srvname, &ea);
+ else
+ client_mode(bpffd, sysname, srvname, &ea);
+
+ return (0);
+}
+
+int
+setupfilter(ifn, ea, server_mode)
+ char *ifn;
+ struct ether_addr *ea;
+ int server_mode;
+{
+ char device[sizeof "/dev/bpf0000000000"];
+ u_int8_t *ep = (u_int8_t *)ea;
+ int fd, idx = 0;
+ u_int u, i;
+ struct ifreq ifr;
+ struct bpf_insn insns[20];
+ struct bpf_program filter;
+
+ idx = 0;
+
+ insns[idx].code = BPF_LD | BPF_H | BPF_ABS;
+ insns[idx].k = 12;
+ insns[idx].jt = insns[idx].jf = 0;
+ idx++;
+
+ insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K;
+ insns[idx].k = ETHERTYPE_PPPOE;
+ insns[idx].jt = 1;
+ insns[idx].jf = 0;
+ idx++;
+
+ insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K;
+ insns[idx].k = ETHERTYPE_PPPOEDISC;
+ insns[idx].jt = 0;
+ insns[idx].jf = 4;
+ idx++;
+
+ insns[idx].code = BPF_LD | BPF_W | BPF_ABS;
+ insns[idx].k = 6;
+ insns[idx].jt = insns[idx].jf = 0;
+ idx++;
+
+ insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K;
+ insns[idx].k =
+ (ep[0] << 24) | (ep[1] << 16) | (ep[2] << 8) | (ep[3] << 0);
+ insns[idx].jt = 0;
+ insns[idx].jf = 3;
+ idx++;
+
+ insns[idx].code = BPF_LD | BPF_H | BPF_ABS;
+ insns[idx].k = 10;
+ insns[idx].jt = insns[idx].jf = 0;
+ idx++;
+
+ insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K;
+ insns[idx].k = ep[4] << 8 | ep[5];
+ insns[idx].jt = 0;
+ insns[idx].jf = 1;
+ idx++;
+
+ insns[idx].code = BPF_RET | BPF_K;
+ insns[idx].k = insns[idx].jt = insns[idx].jf = 0;
+ idx++;
+
+ if (server_mode) {
+ insns[idx].code = BPF_LD | BPF_W | BPF_ABS;
+ insns[idx].k = insns[idx].jt = insns[idx].jf = 0;
+ idx++;
+
+ insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K;
+ insns[idx].k = 0xffffffff;
+ insns[idx].jt = 0;
+ insns[idx].jf = 3;
+ idx++;
+
+ insns[idx].code = BPF_LD | BPF_H | BPF_ABS;
+ insns[idx].k = 4;
+ insns[idx].jt = insns[idx].jf = 0;
+ idx++;
+
+ insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K;
+ insns[idx].k = 0xffff;
+ insns[idx].jt = 4;
+ insns[idx].jf = 0;
+ idx++;
+ }
+
+ insns[idx].code = BPF_LD | BPF_W | BPF_ABS;
+ insns[idx].k = insns[idx].jt = insns[idx].jf = 0;
+ idx++;
+
+ insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K;
+ insns[idx].k = (ep[0]) | (ep[1] << 8) | (ep[3] << 16) | (ep[3] << 24);
+ insns[idx].jt = 0;
+ insns[idx].jf = 3;
+ idx++;
+
+ insns[idx].code = BPF_LD | BPF_H | BPF_ABS;
+ insns[idx].k = 4;
+ insns[idx].jt = insns[idx].jf = 0;
+ idx++;
+
+ insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K;
+ insns[idx].k = (ep[4]) | (ep[5] << 8);
+ insns[idx].jt = 0;
+ insns[idx].jf = 1;
+ idx++;
+
+ insns[idx].code = BPF_RET | BPF_K;
+ insns[idx].k = (u_int)-1;
+ insns[idx].jt = insns[idx].jf = 0;
+ idx++;
+
+ insns[idx].code = BPF_RET | BPF_K;
+ insns[idx].k = (u_int)-1;
+ insns[idx].jt = 0;
+ insns[idx].jf = 0;
+ idx++;
+
+ filter.bf_len = idx;
+ filter.bf_insns = insns;
+
+ for (i = 0; 1; i++) {
+ snprintf(device, sizeof(device), "/dev/bpf%d", i++);
+ fd = open(device, O_RDWR);
+ if (fd < 0) {
+ if (errno != EBUSY)
+ err(EX_IOERR, "%s", device);
+ }
+ else
+ break;
+ }
+
+ u = PPPOE_BPF_BUFSIZ;
+ if (ioctl(fd, BIOCSBLEN, &u) < 0) {
+ close(fd);
+ err(EX_IOERR, "set snaplength");
+ }
+
+ u = 1;
+ if (ioctl(fd, BIOCIMMEDIATE, &u) < 0) {
+ close(fd);
+ err(EX_IOERR, "set immediate");
+ }
+
+ strncpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name));
+ ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';
+ if (ioctl(fd, BIOCSETIF, &ifr) < 0) {
+ close(fd);
+ err(EX_IOERR, "set interface");
+ }
+
+ if (ioctl(fd, BIOCGDLT, &u) < 0) {
+ close(fd);
+ err(EX_IOERR, "get interface type");
+ }
+ if (u != DLT_EN10MB)
+ err(EX_IOERR, "%s is not ethernet", ifn);
+
+ if (ioctl(fd, BIOCSETF, &filter) < 0) {
+ close(fd);
+ err(EX_IOERR, "BIOCSETF");
+ }
+
+ return (fd);
+}
+
+int
+getifhwaddr(ifnhint, ifnambuf, ea)
+ char *ifnhint, *ifnambuf;
+ struct ether_addr *ea;
+{
+ int s;
+ char *inbuf = NULL;
+ struct ifconf ifc;
+ struct ifreq *ifrp, ifreq, req;
+ struct sockaddr_dl *dl;
+ int len = 8192, i;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return (-1);
+ }
+
+ while (1) {
+ ifc.ifc_len= len;
+ ifc.ifc_buf = inbuf = realloc(inbuf, len);
+ if (inbuf == NULL)
+ err(1, "malloc");
+ if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
+ err(1, "gifconf");
+ if (ifc.ifc_len + sizeof(struct ifreq) < len)
+ break;
+ len *= 2;
+ }
+
+ ifrp = ifc.ifc_req;
+ ifreq.ifr_name[0] = '\0';
+ for (i = 0; i < ifc.ifc_len; ) {
+ ifrp = (struct ifreq *)((caddr_t)ifc.ifc_req + i);
+ i += sizeof(ifrp->ifr_name) +
+ (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr) ?
+ ifrp->ifr_addr.sa_len : sizeof(struct sockaddr));
+ if (ifrp->ifr_addr.sa_family != AF_LINK)
+ continue;
+ if (ifnhint != NULL && strncmp(ifnhint, ifrp->ifr_name,
+ sizeof(ifrp->ifr_name)))
+ continue;
+ if (ifnhint == NULL) {
+ strncpy(req.ifr_name, ifrp->ifr_name, IFNAMSIZ);
+ req.ifr_name[IFNAMSIZ-1] = '\0';
+ if (ioctl(s, SIOCGIFFLAGS, &req) < 0)
+ err(EX_IOERR, "get flags");
+ if ((req.ifr_flags & IFF_UP) == 0)
+ continue;
+ }
+ dl = (struct sockaddr_dl *)&ifrp->ifr_addr;
+ if (dl->sdl_type != IFT_ETHER) {
+ if (ifnhint == NULL)
+ continue;
+ fprintf(stderr, "not ethernet interface: %s\n",
+ ifnhint);
+ free(inbuf);
+ close(s);
+ return (-1);
+ }
+ if (dl->sdl_alen != ETHER_ADDR_LEN) {
+ fprintf(stderr, "invalid hwaddr len: %u\n",
+ dl->sdl_alen);
+ free(inbuf);
+ close(s);
+ return (-1);
+ }
+ bcopy(dl->sdl_data + dl->sdl_nlen, ea, sizeof(*ea));
+ strncpy(ifnambuf, ifrp->ifr_name, IFNAMSIZ);
+ ifnambuf[IFNAMSIZ-1] = '\0';
+ free(inbuf);
+ close(s);
+ return (0);
+ }
+ free(inbuf);
+ if (ifnhint == NULL)
+ fprintf(stderr, "no running ethernet found\n");
+ else
+ fprintf(stderr, "no such interface: %s\n", ifnhint);
+ close(s);
+ return (-1);
+}
+
+void
+usage(progname)
+ char *progname;
+{
+ fprintf(stderr, "%s [-s] [-v] [-p system] [-i interface]\n", progname);
+}
+
+void
+child_handler(sig)
+ int sig;
+{
+ int status;
+
+ while (wait3(&status, WNOHANG, NULL) > 0);
+}
+
+int
+signal_init()
+{
+ struct sigaction act;
+
+ if (sigemptyset(&act.sa_mask) < 0)
+ return (-1);
+ act.sa_flags = SA_RESTART;
+ act.sa_handler = child_handler;
+ if (sigaction(SIGCHLD, &act, NULL) < 0)
+ return (-1);
+
+ if (sigemptyset(&act.sa_mask) < 0)
+ return (-1);
+ act.sa_flags = 0;
+ act.sa_handler = SIG_IGN;
+ if (sigaction(SIGPIPE, &act, NULL) < 0)
+ return (-1);
+
+ return (0);
+}
diff --git a/usr.sbin/pppoe/pppoe.h b/usr.sbin/pppoe/pppoe.h
new file mode 100644
index 00000000000..e8f8dacc3b0
--- /dev/null
+++ b/usr.sbin/pppoe/pppoe.h
@@ -0,0 +1,146 @@
+/* $OpenBSD: pppoe.h,v 1.1 2000/06/18 07:30:41 jason Exp $ */
+
+/*
+ * Copyright (c) 2000 Network Security Technologies, Inc. http://www.netsec.net
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Network Security
+ * Technologies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* XXX */
+#ifndef ETHERTYPE_PPPOEDISC
+#define ETHERTYPE_PPPOEDISC 0x8863 /* PPP Over Ethernet Discovery Stage */
+#endif
+#ifndef ETHERTYPE_PPPOE
+#define ETHERTYPE_PPPOE 0x8864 /* PPP Over Ethernet Session Stage */
+#endif
+
+#define PPPOE_MAXSESSIONS 32
+#define PPPOE_BPF_BUFSIZ 65536
+
+struct pppoe_header {
+ u_int8_t vertype; /* PPPoE version (low 4), type (high 4) */
+ u_int8_t code; /* PPPoE code (packet type) */
+ u_int16_t sessionid; /* PPPoE session id */
+ u_int16_t len; /* PPPoE payload length */
+};
+#define PPPOE_MTU (ETHERMTU - sizeof(struct pppoe_header) - 2)
+
+#define PPPOE_VER_S 0 /* Version shift */
+#define PPPOE_VER_M 0x0f /* Version mask */
+#define PPPOE_TYPE_S 4 /* Type shift */
+#define PPPOE_TYPE_M 0xf0 /* Type mask */
+
+#define PPPOE_VER(vt) (((vt) & PPPOE_VER_M) >> PPPOE_VER_S)
+#define PPPOE_TYPE(vt) (((vt) & PPPOE_TYPE_M) >> PPPOE_TYPE_S)
+#define PPPOE_VERTYPE(v,t) \
+ ((((v) << PPPOE_VER_S) & PPPOE_VER_M) | \
+ (((t) << PPPOE_TYPE_S) & PPPOE_TYPE_M))
+
+#define PPPOE_CODE_SESSION 0x00 /* Session */
+#define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */
+#define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */
+#define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */
+#define PPPOE_CODE_PADS 0x65 /* Active Discovery Session-Confirm */
+#define PPPOE_CODE_PADT 0xa7 /* Active Discovery Terminate */
+
+struct pppoe_tag {
+ u_int16_t type; /* Tag Type */
+ u_int16_t len; /* Tag Length */
+ u_int8_t *val; /* Tag Value */
+};
+
+#define PPPOE_TAG_END_OF_LIST 0x0000 /* End Of List */
+#define PPPOE_TAG_SERVICE_NAME 0x0101 /* Service Name */
+#define PPPOE_TAG_AC_NAME 0x0102 /* Access Concentrator Name */
+#define PPPOE_TAG_HOST_UNIQ 0x0103 /* Host Uniq */
+#define PPPOE_TAG_AC_COOKIE 0x0104 /* Access Concentratr Cookie */
+#define PPPOE_TAG_VENDOR_SPEC 0x0105 /* Vendor Specific */
+#define PPPOE_TAG_RELAY_SESSION 0x0110 /* Relay Session Id */
+#define PPPOE_TAG_SERVICE_NAME_ERROR 0x0201 /* Service Name Error */
+#define PPPOE_TAG_AC_SYSTEM_ERROR 0x0202 /* Acc. Concentrator Error */
+#define PPPOE_TAG_GENERIC_ERROR 0x0203 /* Generic Error */
+
+extern int option_verbose;
+extern u_char etherbroadcastaddr[];
+
+void server_mode __P((int, char *, char *, struct ether_addr *));
+int client_mode __P((int, char *, char *, struct ether_addr *));
+
+struct tag_list {
+ LIST_HEAD(, tag_node) thelist;
+};
+
+struct tag_node {
+ LIST_ENTRY(tag_node) next;
+ u_int16_t type;
+ u_int16_t len;
+ u_int8_t *val;
+ int _ref;
+};
+
+void tag_init __P((struct tag_list *));
+void tag_show __P((struct tag_list *));
+void tag_destroy __P((struct tag_list *));
+struct tag_node *tag_lookup __P((struct tag_list *, u_int16_t, int));
+int tag_add __P((struct tag_list *, u_int16_t, u_int16_t, u_int8_t *));
+int tag_pkt __P((struct tag_list *, u_long, u_int8_t *));
+void tag_hton __P((struct tag_list *));
+void tag_ntoh __P((struct tag_list *));
+
+struct pppoe_session {
+ LIST_ENTRY(pppoe_session) s_next;
+ struct ether_addr s_ea; /* remote ethernet mac */
+ u_int16_t s_id; /* session id */
+ int s_fd; /* ttyfd */
+ int s_first;
+};
+
+struct pppoe_session_master {
+ LIST_HEAD(, pppoe_session) sm_sessions; /* session list */
+ int sm_nsessions; /* # of sessions */
+};
+
+extern struct pppoe_session_master session_master;
+
+void session_init __P((void));
+void session_destroy __P((struct pppoe_session *));
+struct pppoe_session *session_new __P((struct ether_addr *));
+struct pppoe_session *session_find_eaid __P((struct ether_addr *, u_int16_t));
+struct pppoe_session *session_find_fd __P((int));
+
+int runppp __P((int, char *));
+int bpf_to_ppp __P((int, u_long, u_int8_t *));
+int ppp_to_bpf __P((int, int, struct ether_addr *, struct ether_addr *,
+ u_int16_t));
+int send_padt __P((int, struct ether_addr *, struct ether_addr *, u_int16_t));
+void recv_debug __P((int, struct ether_addr *,
+ struct ether_header *, struct pppoe_header *, u_long, u_int8_t *));
+void debug_packet __P((u_int8_t *, int));
+
+u_int32_t cookie_bake __P((void));
diff --git a/usr.sbin/pppoe/rfc2516.txt b/usr.sbin/pppoe/rfc2516.txt
new file mode 100644
index 00000000000..5397c863dc3
--- /dev/null
+++ b/usr.sbin/pppoe/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]
+
diff --git a/usr.sbin/pppoe/server.c b/usr.sbin/pppoe/server.c
new file mode 100644
index 00000000000..4ac0a85d419
--- /dev/null
+++ b/usr.sbin/pppoe/server.c
@@ -0,0 +1,478 @@
+/* $OpenBSD: server.c,v 1.1 2000/06/18 07:30:41 jason Exp $ */
+
+/*
+ * Copyright (c) 2000 Network Security Technologies, Inc. http://www.netsec.net
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Network Security
+ * Technologies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <net/bpf.h>
+#include <net/ppp_defs.h>
+#include <errno.h>
+#include <string.h>
+#include <err.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sysexits.h>
+#include <stdlib.h>
+#include <md5.h>
+
+#include "pppoe.h"
+
+#define COOKIE_LEN 4 /* bytes/cookie, must be <= 16 */
+#define COOKIE_MAX 16
+
+static char ac_cookie_key[8];
+
+static void getpackets __P((int, char *, struct ether_addr *));
+
+static void recv_padi __P((int, struct ether_addr *,
+ struct ether_header *, struct pppoe_header *, u_long, u_int8_t *));
+static void recv_padr __P((int, char *, struct ether_addr *,
+ struct ether_header *, struct pppoe_header *, u_long, u_int8_t *));
+static void recv_padt __P((int, struct ether_addr *,
+ struct ether_header *, struct pppoe_header *, u_long, u_int8_t *));
+
+static void send_pado __P((int, struct ether_addr *,
+ struct ether_header *, struct pppoe_header *, u_long, u_int8_t *));
+static void send_pads __P((int, char *, struct ether_addr *,
+ struct ether_header *, struct pppoe_header *, u_long, u_int8_t *));
+static void key_gen __P((void));
+static u_int8_t *key_make __P((u_int8_t *, int, u_int8_t *, int));
+static int key_cmp __P((u_int8_t *, int, u_int8_t *, int, u_int8_t *, int));
+
+void
+server_mode(bpffd, sysname, srvname, ea)
+ int bpffd;
+ char *sysname, *srvname;
+ struct ether_addr *ea;
+{
+ struct pppoe_session *ses;
+ fd_set rfds;
+ int n;
+
+ key_gen();
+
+ while (1) {
+reselect:
+ FD_ZERO(&rfds);
+ FD_SET(bpffd, &rfds);
+ n = bpffd;
+ ses = LIST_FIRST(&session_master.sm_sessions);
+ while (ses) {
+ if (ses->s_fd != -1) {
+ FD_SET(ses->s_fd, &rfds);
+ if (ses->s_fd > n)
+ n = ses->s_fd;
+ }
+ ses = LIST_NEXT(ses, s_next);
+ }
+
+ n = select(n+1, &rfds, NULL, NULL, NULL);
+ if (n < 0) {
+ if (errno == EINTR)
+ goto reselect;
+ err(EX_IOERR, "select");
+ return;
+ }
+ if (n == 0)
+ continue;
+ if (FD_ISSET(bpffd, &rfds)) {
+ n--;
+ getpackets(bpffd, sysname, ea);
+ }
+ if (n == 0)
+ continue;
+
+ ses = LIST_FIRST(&session_master.sm_sessions);
+ while (ses) {
+ if (ses->s_fd != -1 && FD_ISSET(ses->s_fd, &rfds)) {
+ if (ppp_to_bpf(bpffd, ses->s_fd, ea,
+ &ses->s_ea, ses->s_id) < 0) {
+ send_padt(bpffd, ea,
+ &ses->s_ea, ses->s_id);
+ session_destroy(ses);
+ }
+ n--;
+ if (n == 0)
+ break;
+ }
+ ses = LIST_NEXT(ses, s_next);
+ }
+ }
+}
+
+void
+key_gen()
+{
+ u_int32_t r;
+
+ r = arc4random();
+ memcpy(ac_cookie_key, &r, sizeof(r));
+ r = arc4random();
+ memcpy(ac_cookie_key + sizeof(r), &r, sizeof(r));
+}
+
+u_int8_t *
+key_make(in1, in1len, in2, in2len)
+ u_int8_t *in1, *in2;
+ int in1len, in2len;
+{
+ u_int8_t *p;
+ MD5_CTX ctx;
+
+ p = (u_int8_t *)malloc(COOKIE_MAX);
+ if (p == NULL)
+ return (p);
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, in1, in1len);
+ MD5Update(&ctx, in2, in2len);
+ MD5Final(p, &ctx);
+ return (p);
+}
+
+int
+key_cmp(k, klen, in1, in1len, in2, in2len)
+ u_int8_t *k, *in1, *in2;
+ int klen, in1len, in2len;
+{
+ u_int8_t *p;
+ int r;
+
+ if (klen != COOKIE_LEN)
+ return (-1);
+
+ p = key_make(in1, in1len, in2, in2len);
+ if (p == NULL)
+ return (-1);
+
+ r = memcmp(k, p, COOKIE_LEN);
+ free(p);
+ return (r);
+}
+
+static void
+getpackets(bpffd, sysname, ea)
+ int bpffd;
+ char *sysname;
+ struct ether_addr *ea;
+{
+ static u_int8_t *pktbuf;
+ u_int8_t *mpkt, *pkt, *epkt;
+ struct ether_header eh;
+ struct pppoe_header ph;
+ struct bpf_hdr *bh;
+ int rlen;
+ u_long len;
+
+ if (pktbuf == NULL) {
+ pktbuf = (u_int8_t *)malloc(PPPOE_BPF_BUFSIZ);
+ if (pktbuf == NULL)
+ return;
+ }
+
+ rlen = read(bpffd, pktbuf, PPPOE_BPF_BUFSIZ);
+ if (rlen < 0)
+ return;
+
+ pkt = pktbuf;
+ epkt = pkt + rlen;
+ while (pkt < epkt) {
+ bh = (struct bpf_hdr *)pkt;
+ len = bh->bh_caplen;
+ mpkt = pkt + bh->bh_hdrlen;
+
+ /* Pull out ethernet header */
+ if (len < sizeof(struct ether_header))
+ goto next;
+ bcopy(mpkt, &eh, sizeof(struct ether_header));
+ eh.ether_type = ntohs(eh.ether_type);
+ len -= sizeof(struct ether_header);
+ mpkt += sizeof(struct ether_header);
+
+ /* Pull out pppoe header */
+ if (len < sizeof(struct pppoe_header))
+ goto next;
+ bcopy(mpkt, &ph, sizeof(struct pppoe_header));
+ mpkt += sizeof(struct pppoe_header);
+ len -= sizeof(struct pppoe_header);
+ ph.len = ntohs(ph.len);
+ ph.sessionid = ntohs(ph.sessionid);
+
+ if (PPPOE_VER(ph.vertype) != 1 ||
+ PPPOE_TYPE(ph.vertype) != 1)
+ goto next;
+
+ if (len > ph.len)
+ len = ph.len;
+
+ if (eh.ether_type == ETHERTYPE_PPPOEDISC) {
+ /* Discovery Stage */
+ switch (ph.code) {
+ case PPPOE_CODE_PADI:
+ recv_padi(bpffd, ea, &eh, &ph, len, mpkt);
+ break;
+ case PPPOE_CODE_PADR:
+ recv_padr(bpffd, sysname, ea, &eh, &ph,
+ len, mpkt);
+ break;
+ case PPPOE_CODE_PADT:
+ recv_padt(bpffd, ea, &eh, &ph, len, mpkt);
+ break;
+ default:
+ recv_debug(bpffd, ea, &eh, &ph, len, mpkt);
+ }
+ }
+ else if (eh.ether_type == ETHERTYPE_PPPOE) {
+ /* Session Stage */
+ struct pppoe_session *s;
+
+ s = session_find_eaid(
+ (struct ether_addr *)&eh.ether_shost[0],
+ ph.sessionid);
+ if (s != NULL && bpf_to_ppp(s->s_fd, len, mpkt) <= 0)
+ session_destroy(s);
+ }
+next:
+ pkt += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
+ }
+}
+
+static void
+recv_padi(bpffd, ea, eh, ph, pktlen, pktbuf)
+ int bpffd;
+ struct ether_addr *ea;
+ struct ether_header *eh;
+ struct pppoe_header *ph;
+ u_long pktlen;
+ u_int8_t *pktbuf;
+{
+ struct tag_list tl;
+
+ if (ph->sessionid != 0)
+ return;
+ if (bcmp(&eh->ether_dhost[0], etherbroadcastaddr, ETHER_ADDR_LEN))
+ return;
+
+ tag_init(&tl);
+ if (tag_pkt(&tl, pktlen, pktbuf) < 0)
+ goto out;
+
+ if (tag_lookup(&tl, PPPOE_TAG_SERVICE_NAME, 1) != NULL)
+ goto out;
+
+ send_pado(bpffd, ea, eh, ph, pktlen, pktbuf);
+
+out:
+ tag_destroy(&tl);
+}
+
+static void
+send_pado(bpffd, ea, eh, ph, pktlen, pktbuf)
+ int bpffd;
+ struct ether_addr *ea;
+ struct ether_header *eh;
+ struct pppoe_header *ph;
+ u_long pktlen;
+ u_int8_t *pktbuf;
+{
+ struct pppoe_tag ktag, htag;
+ char hn[MAXHOSTNAMELEN];
+ u_int8_t *k = NULL;
+ struct iovec v[7];
+ int idx = 0;
+
+ memcpy(&eh->ether_dhost[0], &eh->ether_shost[0], ETHER_ADDR_LEN);
+ memcpy(&eh->ether_shost[0], ea, ETHER_ADDR_LEN);
+ eh->ether_type = htons(eh->ether_type);
+ v[idx].iov_base = eh; v[idx].iov_len = sizeof(*eh); idx++;
+
+ ph->code = PPPOE_CODE_PADO;
+ v[idx].iov_base = ph; v[idx].iov_len = sizeof(*ph); idx++;
+
+ v[idx].iov_base = pktbuf; v[idx].iov_len = pktlen; idx++;
+
+ if (gethostname(hn, sizeof(hn)) < 0)
+ return;
+ htag.len = strlen(hn);
+ htag.type = htons(PPPOE_TAG_AC_NAME);
+ htag.val = hn;
+ v[idx].iov_base = &htag;
+ v[idx].iov_len = sizeof(htag.len) + sizeof(htag.type);
+ idx++;
+ v[idx].iov_base = hn; v[idx].iov_len = htag.len; idx++;
+ ph->len += sizeof(htag.len) + sizeof(htag.type) + htag.len;
+ htag.len = htons(htag.len);
+
+ k = key_make(&eh->ether_dhost[0], ETHER_ADDR_LEN, ac_cookie_key,
+ sizeof(ac_cookie_key));
+ if (k == NULL)
+ return;
+ ktag.type = htons(PPPOE_TAG_AC_COOKIE);
+ ktag.len = COOKIE_LEN;
+ ktag.val = k;
+ v[idx].iov_base = &ktag;
+ v[idx].iov_len = sizeof(ktag.len) + sizeof(ktag.type);
+ idx++;
+ v[idx].iov_base = k; v[idx].iov_len = COOKIE_LEN; idx++;
+ ph->len += sizeof(ktag.len) + sizeof(ktag.type) + COOKIE_LEN;
+ ktag.len = htons(COOKIE_LEN);
+
+ ph->len = htons(ph->len);
+
+ writev(bpffd, v, idx);
+
+ if (k)
+ free(k);
+}
+
+static void
+recv_padr(bpffd, sysname, ea, eh, ph, pktlen, pktbuf)
+ int bpffd;
+ char *sysname;
+ struct ether_addr *ea;
+ struct ether_header *eh;
+ struct pppoe_header *ph;
+ u_long pktlen;
+ u_int8_t *pktbuf;
+{
+ struct tag_list tl;
+ struct tag_node *n;
+
+ if (ph->sessionid != 0)
+ return;
+
+ tag_init(&tl);
+ if (tag_pkt(&tl, pktlen, pktbuf) < 0)
+ return;
+
+ n = tag_lookup(&tl, PPPOE_TAG_AC_COOKIE, 0);
+ if (n == NULL)
+ return;
+ if (key_cmp(n->val, n->len, &eh->ether_shost[0], ETHER_ADDR_LEN,
+ ac_cookie_key, sizeof(ac_cookie_key)))
+ return;
+
+ send_pads(bpffd, sysname, ea, eh, ph, pktlen, pktbuf);
+
+ tag_destroy(&tl);
+}
+
+static void
+send_pads(bpffd, sysname, ea, eh, ph, pktlen, pktbuf)
+ int bpffd;
+ char *sysname;
+ struct ether_addr *ea;
+ struct ether_header *eh;
+ struct pppoe_header *ph;
+ u_long pktlen;
+ u_int8_t *pktbuf;
+{
+ char hn[MAXHOSTNAMELEN];
+ struct iovec v[16];
+ struct pppoe_session *s;
+ struct pppoe_tag htag;
+ int idx = 0;
+
+ s = session_new((struct ether_addr *)&eh->ether_shost[0]);
+ if (s == NULL)
+ return;
+
+ memcpy(&eh->ether_dhost[0], &eh->ether_shost[0], ETHER_ADDR_LEN);
+ memcpy(&eh->ether_shost[0], ea, ETHER_ADDR_LEN);
+ eh->ether_type = htons(eh->ether_type);
+ v[idx].iov_base = eh; v[idx].iov_len = sizeof(*eh); idx++;
+
+ ph->code = PPPOE_CODE_PADS;
+ ph->sessionid = htons(s->s_id);
+ if (gethostname(hn, sizeof(hn)) < 0)
+ return;
+ v[idx].iov_base = ph; v[idx].iov_len = sizeof(*ph); idx++;
+
+ v[idx].iov_base = pktbuf; v[idx].iov_len = pktlen; idx++;
+
+ htag.len = strlen(hn);
+ htag.type = htons(PPPOE_TAG_AC_NAME);
+ htag.val = hn;
+ v[idx].iov_base = &htag;
+ v[idx].iov_len = sizeof(htag.len) + sizeof(htag.type);
+ idx++;
+ v[idx].iov_base = hn; v[idx].iov_len = htag.len; idx++;
+ ph->len += sizeof(htag.len) + sizeof(htag.type) + htag.len;
+ htag.len = htons(htag.len);
+
+ ph->len = htons(ph->len);
+
+ writev(bpffd, v, idx);
+
+ s->s_fd = runppp(bpffd, sysname);
+ if (s->s_fd < 0) {
+ /* XXX Send PADT with Generic-Error */
+ s->s_fd = -1;
+ }
+}
+
+static void
+recv_padt(bpffd, ea, eh, ph, pktlen, pktbuf)
+ int bpffd;
+ struct ether_addr *ea;
+ struct ether_header *eh;
+ struct pppoe_header *ph;
+ u_long pktlen;
+ u_int8_t *pktbuf;
+{
+ struct pppoe_session *s;
+ struct tag_list tl;
+
+ tag_init(&tl);
+ if (tag_pkt(&tl, pktlen, pktbuf) < 0)
+ goto out;
+
+ s = session_find_eaid((struct ether_addr *)&eh->ether_shost[0],
+ ph->sessionid);
+ if (s == NULL)
+ goto out;
+ session_destroy(s);
+
+out:
+ tag_destroy(&tl);
+}
diff --git a/usr.sbin/pppoe/session.c b/usr.sbin/pppoe/session.c
new file mode 100644
index 00000000000..294ec3d84f1
--- /dev/null
+++ b/usr.sbin/pppoe/session.c
@@ -0,0 +1,140 @@
+/* $OpenBSD: session.c,v 1.1 2000/06/18 07:30:41 jason Exp $ */
+
+/*
+ * Copyright (c) 2000 Network Security Technologies, Inc. http://www.netsec.net
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Network Security
+ * Technologies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <net/bpf.h>
+#include <errno.h>
+#include <string.h>
+#include <err.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sysexits.h>
+#include <stdlib.h>
+
+#include "pppoe.h"
+
+struct pppoe_session_master session_master;
+
+void
+session_init(void)
+{
+ LIST_INIT(&session_master.sm_sessions);
+ session_master.sm_nsessions = 0;
+}
+
+void
+session_destroy(struct pppoe_session *s)
+{
+ if (s->s_fd != -1)
+ close(s->s_fd);
+ LIST_REMOVE(s, s_next);
+ free(s);
+}
+
+struct pppoe_session *
+session_new(struct ether_addr *ea)
+{
+ struct pppoe_session *s;
+ u_int32_t x;
+ u_int16_t id = 1;
+ int tries = 1000;
+
+ if (session_master.sm_nsessions == PPPOE_MAXSESSIONS)
+ return (NULL);
+
+ while (tries--) {
+ x = cookie_bake();
+ id = ((x >> 16) & 0xffff) ^ (x & 0xffff);
+ s = LIST_FIRST(&session_master.sm_sessions);
+ while (s) {
+ if (memcmp(ea, &s->s_ea, ETHER_ADDR_LEN) == 0 &&
+ s->s_id == id)
+ break;
+ s = LIST_NEXT(s, s_next);
+ }
+ if (s == NULL)
+ break;
+ }
+ if (tries == 0)
+ return (NULL);
+
+ s = (struct pppoe_session *)malloc(sizeof(*s));
+ if (s == NULL)
+ return (NULL);
+
+ s->s_id = id;
+ s->s_fd = -1;
+ s->s_first = 1;
+ memcpy(&s->s_ea, ea, ETHER_ADDR_LEN);
+ LIST_INSERT_HEAD(&session_master.sm_sessions, s, s_next);
+
+ return (s);
+}
+
+struct pppoe_session *
+session_find_eaid(struct ether_addr *ea, u_int16_t id)
+{
+ struct pppoe_session *s;
+
+ s = LIST_FIRST(&session_master.sm_sessions);
+ while (s) {
+ if (memcmp(ea, &s->s_ea, ETHER_ADDR_LEN) == 0 && s->s_id == id)
+ return (s);
+ s = LIST_NEXT(s, s_next);
+ }
+ return (NULL);
+}
+
+struct pppoe_session *
+session_find_fd(int fd)
+{
+ struct pppoe_session *s;
+ s = LIST_FIRST(&session_master.sm_sessions);
+ while (s) {
+ if (s->s_fd == fd)
+ return (s);
+ s = LIST_NEXT(s, s_next);
+ }
+ return (NULL);
+}
diff --git a/usr.sbin/pppoe/tag.c b/usr.sbin/pppoe/tag.c
new file mode 100644
index 00000000000..c1968a7b93a
--- /dev/null
+++ b/usr.sbin/pppoe/tag.c
@@ -0,0 +1,188 @@
+/* $OpenBSD: tag.c,v 1.1 2000/06/18 07:30:41 jason Exp $ */
+
+/*
+ * Copyright (c) 2000 Network Security Technologies, Inc. http://www.netsec.net
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Network Security
+ * Technologies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <net/bpf.h>
+#include <errno.h>
+#include <string.h>
+#include <err.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sysexits.h>
+#include <stdlib.h>
+
+#include "pppoe.h"
+
+void
+tag_init(struct tag_list *l)
+{
+ LIST_INIT(&l->thelist);
+}
+
+void
+tag_destroy(struct tag_list *l)
+{
+ struct tag_node *p;
+
+ while (1) {
+ p = LIST_FIRST(&l->thelist);
+ if (p == NULL)
+ break;
+ p->_ref--;
+ if (p->_ref == 0 && p->val)
+ free(p->val);
+ LIST_REMOVE(p, next);
+ free(p);
+ }
+}
+
+struct tag_node *
+tag_lookup(struct tag_list *l, u_int16_t type, int idx)
+{
+ struct tag_node *p;
+
+ p = LIST_FIRST(&l->thelist);
+ while (p != NULL) {
+ if (p->type == type) {
+ if (idx == 0)
+ break;
+ idx--;
+ }
+ p = LIST_NEXT(p, next);
+ }
+ return (p);
+}
+
+int
+tag_add(struct tag_list *l, u_int16_t type, u_int16_t len, u_int8_t *val)
+{
+ struct tag_node *p;
+
+ p = (struct tag_node *)malloc(sizeof(*p));
+ if (p == NULL)
+ return (-1);
+ if (len) {
+ p->val = (u_int8_t *)malloc(len);
+ if (p->val == NULL) {
+ free(p);
+ return (-1);
+ }
+ memcpy(p->val, val, len);
+ }
+ else
+ p->val = NULL;
+ p->type = type;
+ p->len = len;
+ p->_ref = 1;
+ LIST_INSERT_HEAD(&l->thelist, p, next);
+ return (0);
+}
+
+int
+tag_pkt(struct tag_list *l, u_long pktlen, u_int8_t *pkt)
+{
+ u_int16_t ttype, tlen;
+
+ while (pktlen != 0) {
+ if (pktlen < sizeof(u_int16_t))
+ break;
+ ttype = pkt[1] | (pkt[0] << 8);
+ pkt += sizeof(u_int16_t);
+ pktlen -= sizeof(u_int16_t);
+
+ if (pktlen < sizeof(u_int16_t))
+ break;
+ tlen = pkt[1] | (pkt[0] << 8);
+ pkt += sizeof(u_int16_t);
+ pktlen -= sizeof(u_int16_t);
+
+ if (pktlen < tlen)
+ break;
+
+ if (tag_add(l, ttype, tlen, pkt) < 0)
+ return (-1);
+ pkt += tlen;
+ pktlen -= tlen;
+ }
+
+ if (pktlen != 0)
+ return (-1);
+ return (0);
+}
+
+void
+tag_show(struct tag_list *l)
+{
+ struct tag_node *p;
+ int i;
+
+ for (p = LIST_FIRST(&l->thelist); p; p = LIST_NEXT(p, next)) {
+ printf("\ttag type=0x%04x, length=%d", p->type, p->len);
+ for (i = 0; i < p->len; i++)
+ printf("%c%02x", (i == 0) ? ' ' : ':', p->val[i]);
+ printf("\n");
+ }
+}
+
+void
+tag_hton(struct tag_list *l)
+{
+ struct tag_node *p;
+
+ for (p = LIST_FIRST(&l->thelist); p; p = LIST_NEXT(p, next)) {
+ p->len = htons(p->len);
+ p->type = htons(p->type);
+ }
+}
+
+void
+tag_ntoh(struct tag_list *l)
+{
+ struct tag_node *p;
+
+ for (p = LIST_FIRST(&l->thelist); p; p = LIST_NEXT(p, next)) {
+ p->len = htons(p->len);
+ p->type = htons(p->type);
+ }
+}