Hi All,
The following is tested with:
Stock 5.0 as client & server.
These modification to 5.0 client & server.
Recent pppoe(4) patches for RFC 4638 support applied to 5.0 as the client.
It appears to be broken in with -current from a few days ago + these
mods as the server; although if I run ktrace on the server's spawned
ppp(8) then it appears to work just after the ktrace attaches...
To test pppoe(8) changes I use the following configuration files:
/etc/ppp/ppp.secret:
user1 secret123
/etc/ppp/ppp.conf:
default:
set log Phase Chat LCP IPCP CCP tun command
disable ipv6cp
pppoe1:
set device "!/usr/sbin/pppoe -i em1"
set mtu max 1492
set mru max 1492
set speed sync
disable acfcomp protocomp
deny acfcomp
set authname user1
set authkey secret123
pppoe2:
set device "!/usr/sbin/pppoe -i em1 -m 1500"
set mtu max 1500
set mru max 1500
set speed sync
disable acfcomp protocomp
deny acfcomp
set authname user1
set authkey secret123
pppoes1:
set mtu max 1492
set mru max 1492
set speed sync
disable acfcomp protocomp
deny acfcomp
set ifaddr 10.0.0.1 10.0.1.1-10.255.255.254 255.255.255.255
enable pap
pppoes2:
set mtu max 1500
set mru max 1500
set speed sync
disable acfcomp protocomp
deny acfcomp
set ifaddr 10.0.0.1 10.0.1.1-10.255.255.254 255.255.255.255
enable pap
And, for example, I will bring em1 up on the client and server with:
# ifconfig em1 mtu 2000 up
then go through the various combinations of
server# pppoe -p pppoes1 -i em1 -s
client# ppp pppoe1
ppp> open
...
and
server# pppoe -p pppoes2 -i em1 -m 1500 -s
client# ppp pppoe2
ppp> open
...
For testing the recent pppoe(4) modifications as the client I used:
# ifconfig em1 mtu 1500 up
# ifconfig pppoe0 0.0.0.0 0.0.0.1 netmask 255.255.255.255 \
pppoedev em1 authproto pap authname user1 authkey secret123
and subsequently:
# ifconfig em1 mtu 1508 up
# ifconfig pppoe0 down
# ifconfig pppoe0 mtu 1500 up
with both:
server# pppoe -p pppoes1 -i em1 -s
and
server# pppoe -p pppoes2 -i em1 -m 1500 -s
-- ben
Index: client.c
===================================================================
RCS file: /cvs/src/usr.sbin/pppoe/client.c,v
retrieving revision 1.23
diff -u -p -r1.23 client.c
--- client.c 4 Jul 2011 16:29:35 -0000 1.23
+++ client.c 29 Jan 2012 13:59:40 -0000
@@ -1,4 +1,4 @@
-/* $OpenBSD: client.c,v 1.23 2011/07/04 16:29:35 sthen Exp $ */
+/* $OpenBSD: client.c,v 1.24 2011/11/05 09:20:36 yasuoka Exp $ */
/*
* Copyright (c) 2000 Network Security Technologies, Inc.
http://www.netsec.net
@@ -28,10 +28,7 @@
#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>
@@ -41,10 +38,7 @@
#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 <signal.h>
@@ -56,6 +50,7 @@
u_int32_t client_cookie;
u_int16_t client_sessionid;
+u_int16_t client_mtu;
int pppfd, client_state;
static int getpackets(int, u_int8_t *, u_int8_t *, struct ether_addr *,
@@ -86,6 +81,7 @@ client_mode(int bfd, u_int8_t *sysname,
pppfd = -1;
client_sessionid = 0xffff;
client_state = -1;
+ client_mtu = 0;
r = send_padi(bfd, myea, srvname);
if (r <= 0)
@@ -150,13 +146,14 @@ client_mode(int bfd, u_int8_t *sysname,
static int
send_padi(int fd, struct ether_addr *ea, u_int8_t *srv)
{
- struct iovec iov[10];
+ struct iovec iov[12];
struct pppoe_header ph = {
PPPOE_VERTYPE(1, 1),
PPPOE_CODE_PADI, 0, 0
};
- struct pppoe_tag thost, tserv;
+ struct pppoe_tag thost, tserv, tmaxpayload;
u_int16_t etype = htons(ETHERTYPE_PPPOEDISC);
+ u_int16_t maxpayload;
int i = 0;
/* ether_header */
@@ -196,6 +193,21 @@ send_padi(int fd, struct ether_addr *ea,
}
tserv.len = htons(tserv.len);
+ /* ppp-max-payload tag (optional) */
+ if (rfc_4638_mtu > PPPOE_MIN_MTU) {
+ tmaxpayload.type = htons(PPPOE_TAG_PPP_MAX_PAYLOAD);
+ tmaxpayload.len = htons(sizeof(maxpayload));
+ tmaxpayload.val = (u_int8_t*) &maxpayload;
+ maxpayload = htons(rfc_4638_mtu);
+ iov[i].iov_base = &tmaxpayload;
+ iov[i++].iov_len = sizeof(tmaxpayload.len) +
sizeof(tmaxpayload.type);
+ iov[i].iov_base = &maxpayload;
+ iov[i++].iov_len = sizeof(maxpayload);
+ ph.len += sizeof(tmaxpayload.len) + sizeof(tmaxpayload.type) +
+sizeof(maxpayload);
+ }
+
+
ph.len = htons(ph.len);
client_state = STATE_EXPECT_PADO;
@@ -208,9 +220,10 @@ send_padr(int bfd, u_int8_t *srv, struct
struct ether_addr *rmea, struct ether_header *eh,
struct pppoe_header *ph, struct tag_list *tl)
{
- struct iovec iov[12];
+ struct iovec iov[14];
u_int16_t etype = htons(ETHERTYPE_PPPOEDISC);
- struct pppoe_tag hutag, svtag;
+ struct pppoe_tag hutag, svtag, mptag;
+ u_int16_t maxpayload = htons(client_mtu);
struct tag_node *n;
int idx = 0, slen;
@@ -251,6 +264,18 @@ send_padr(int bfd, u_int8_t *srv, struct
iov[idx++].iov_len = slen;
}
+ /* PPP-Max-Payload */
+ if (client_mtu > 0) {
+ mptag.type = htons(PPPOE_TAG_PPP_MAX_PAYLOAD);
+ mptag.len = htons(sizeof(maxpayload));
+ iov[idx].iov_base = &mptag;
+ iov[idx++].iov_len = sizeof(mptag.type) + sizeof(mptag.len);
+ iov[idx].iov_base = &maxpayload;
+ iov[idx++].iov_len = sizeof(maxpayload);
+ ph->len += sizeof(mptag.type) + sizeof(mptag.len) +
sizeof(maxpayload);
+ }
+
+
n = tag_lookup(tl, PPPOE_TAG_RELAY_SESSION, 0);
if (n != NULL) {
iov[idx].iov_base = &n->type;
@@ -413,6 +438,18 @@ recv_pado(int bfd, u_int8_t *srv, struct
if (bcmp(n->val, &client_cookie, sizeof(client_cookie)))
goto out;
+ n = tag_lookup(&tl, PPPOE_TAG_PPP_MAX_PAYLOAD, 0);
+ if (n != NULL) {
+ client_mtu = n->val[1] | (n->val[0] << 8);
+ if (client_mtu > rfc_4638_mtu) {
+ client_mtu = rfc_4638_mtu;
+ } else if (client_mtu < PPPOE_MIN_MTU) {
+ client_mtu = PPPOE_MIN_MTU;
+ }
+ } else {
+ client_mtu = 0;
+ }
+
r = 0;
slen = (srv == NULL) ? 0 : strlen((char *)srv);
while ((n = tag_lookup(&tl, PPPOE_TAG_SERVICE_NAME, r)) != NULL) {
@@ -468,6 +505,18 @@ recv_pads(int bfd, u_int8_t *srv, u_int8
goto out;
if (bcmp(n->val, &client_cookie, sizeof(client_cookie)))
goto out;
+
+ n = tag_lookup(&tl, PPPOE_TAG_PPP_MAX_PAYLOAD, 0);
+ if (n != NULL && n->len == sizeof(client_mtu)) {
+ client_mtu = n->val[1] | (n->val[0] << 8);
+ if (client_mtu > rfc_4638_mtu ||
+ client_mtu < PPPOE_MIN_MTU) {
+ /* error; fallback */
+ client_mtu = 0;
+ }
+ } else {
+ client_mtu = 0;
+ }
if (ph->sessionid == 0) {
timer_clr();
Index: common.c
===================================================================
RCS file: /cvs/src/usr.sbin/pppoe/common.c,v
retrieving revision 1.12
diff -u -p -r1.12 common.c
--- common.c 6 May 2004 20:29:04 -0000 1.12
+++ common.c 29 Jan 2012 13:59:41 -0000
@@ -1,4 +1,4 @@
-/* $OpenBSD: common.c,v 1.12 2004/05/06 20:29:04 deraadt Exp $ */
+/* $OpenBSD: common.c,v 1.13 2011/11/05 09:20:36 yasuoka Exp $ */
/*
* Copyright (c) 2000 Network Security Technologies, Inc.
http://www.netsec.net
@@ -28,10 +28,7 @@
#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>
@@ -41,10 +38,8 @@
#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 <md5.h>
@@ -143,7 +138,7 @@ ppp_to_bpf(int bfd, int pppfd, struct et
int r;
if (pktbuf == NULL) {
- pktbuf = (u_int8_t *)malloc(PPPOE_MTU);
+ pktbuf = (u_int8_t *)malloc(rfc_4638_mtu + PPPOE_MTU_DIFF);
if (pktbuf == NULL)
return (-1);
}
@@ -151,7 +146,7 @@ ppp_to_bpf(int bfd, int pppfd, struct et
iov[0].iov_base = trash;
iov[0].iov_len = 2;
iov[1].iov_base = pktbuf;
- iov[1].iov_len = PPPOE_MTU;
+ iov[1].iov_len = rfc_4638_mtu + PPPOE_MTU_DIFF;
r = readv(pppfd, iov, 2);
if (r <= 0)
return (-1);
Index: debug.c
===================================================================
RCS file: /cvs/src/usr.sbin/pppoe/debug.c,v
retrieving revision 1.2
diff -u -p -r1.2 debug.c
--- debug.c 4 Jun 2003 04:46:13 -0000 1.2
+++ debug.c 29 Jan 2012 13:59:41 -0000
@@ -156,6 +156,9 @@ debug_packet(u_int8_t *pkt, int len)
case PPPOE_TAG_RELAY_SESSION:
printf("relay-session");
break;
+ case PPPOE_TAG_PPP_MAX_PAYLOAD:
+ printf("ppp-max-payload");
+ break;
case PPPOE_TAG_SERVICE_NAME_ERROR:
printf("service-name-error");
break;
Index: pppoe.8
===================================================================
RCS file: /cvs/src/usr.sbin/pppoe/pppoe.8,v
retrieving revision 1.24
diff -u -p -r1.24 pppoe.8
--- pppoe.8 20 Apr 2011 12:53:50 -0000 1.24
+++ pppoe.8 29 Jan 2012 13:59:41 -0000
@@ -37,6 +37,7 @@
.Op Fl i Ar interface
.Op Fl n Ar service
.Op Fl p Ar system
+.Op Fl m Ar mtu
.Sh DESCRIPTION
The
.Nm pppoe
@@ -67,6 +68,14 @@ This argument is passed, uninterpreted,
It can be used to specify the configuration data to be used for
PPP Over Ethernet connections.
This option is only used in server mode.
+.It Fl m Ar mtu
+Attempt to negotiate a higher MTU, using RFC 4638. It is your
+responsibility to ensure that the ethernet
+.Ar interface
+supports jumbo frames and is configured with an MTU at
+least 8 bytes greater than this or 1500, and that
+.Xr ppp 8
+is also configured to support the same maximum MTU/MRU.
.It Fl s
If this option is specified,
.Nm
@@ -223,6 +232,13 @@ to adjust the maximum segment size on ou
.%T A Method for Transmitting PPP Over Ethernet (PPPoE)
.%A L. Mamakos, et al.
.Re
+.Rs
+.%R RFC 4638
+.%T Accommodating a Maximum Transit Unit/Maximum Receive Unit
+(MTU/MRU) Greater Than 1492 in the Point-to-Point Protocol over
+Ethernet (PPPoE)
+.%A P. Arberg, et al.
+.Re
.Sh HISTORY
This implementation of
.Nm pppoe
@@ -238,6 +254,11 @@ program was written by
of
.An Network Security Technologies, Inc.\&
.Aq http://www.netsec.net .
+.Sh CAVEATS
+RFC 4638 negotiation is only aware of the MTU configured on the endpoints,
+but not the maximum MTU supported on the path between them.
+If the path cannot pass the larger Ethernet frames, negotiation will
succeed
+but the connection will not function correctly.
.Sh BUGS
This software runs completely in user mode.
As such it will have much more overhead than a kernel implementation.
Index: pppoe.c
===================================================================
RCS file: /cvs/src/usr.sbin/pppoe/pppoe.c,v
retrieving revision 1.18
diff -u -p -r1.18 pppoe.c
--- pppoe.c 30 Apr 2011 18:47:48 -0000 1.18
+++ pppoe.c 29 Jan 2012 13:59:41 -0000
@@ -1,4 +1,4 @@
-/* $OpenBSD: pppoe.c,v 1.18 2011/04/30 18:47:48 nicm Exp $ */
+/* $OpenBSD: pppoe.c,v 1.19 2011/11/05 09:20:36 yasuoka Exp $ */
/*
* Copyright (c) 2000 Network Security Technologies, Inc.
http://www.netsec.net
@@ -27,8 +27,6 @@
#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>
@@ -46,12 +44,13 @@
#include <pwd.h>
#include <unistd.h>
#include <sysexits.h>
-#include <stdlib.h>
#include <signal.h>
#include <ifaddrs.h>
+#include <stdlib.h>
#include "pppoe.h"
+u_int16_t rfc_4638_mtu = PPPOE_MIN_MTU;
int option_verbose = 0;
u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -75,10 +74,12 @@ main(int argc, char **argv)
int bpffd, smode = 0, c;
struct passwd *pw;
+ rfc_4638_mtu = PPPOE_MIN_MTU;
+
if ((pw = getpwnam("_ppp")) == NULL)
err(EX_CONFIG, "getpwnam(\"_ppp\")");
- while ((c = getopt(argc, argv, "svi:n:p:")) != -1) {
+ while ((c = getopt(argc, argv, "svm:i:n:p:")) != -1) {
switch (c) {
case 'i':
if (ifname != NULL) {
@@ -94,6 +95,11 @@ main(int argc, char **argv)
}
srvname = (u_int8_t *)optarg;
break;
+ case 'm':
+ rfc_4638_mtu = (u_int16_t) atoi(optarg);
+ if (rfc_4638_mtu < PPPOE_MIN_MTU)
+ rfc_4638_mtu = PPPOE_MIN_MTU;
+ break;
case 'p':
if (sysname != NULL) {
usage();
@@ -415,6 +421,8 @@ getifhwaddr(char *ifnhint, char *ifnambu
{
struct sockaddr_dl *dl;
struct ifaddrs *ifap, *ifa;
+ struct ifreq ifr;
+ int fd;
if (getifaddrs(&ifap) != 0) {
perror("getifaddrs");
@@ -445,6 +453,34 @@ getifhwaddr(char *ifnhint, char *ifnambu
freeifaddrs(ifap);
return (-1);
}
+
+ /* check and reduce interface MTU per RFC 4638 */
+ if (rfc_4638_mtu > PPPOE_MIN_MTU) {
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd == -1) {
+ rfc_4638_mtu = PPPOE_MIN_MTU;
+ goto choose;
+ }
+ strlcpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ);
+ if (ioctl(fd, SIOCGIFMTU, &ifr) == -1) {
+ close(fd);
+ rfc_4638_mtu = PPPOE_MIN_MTU;
+ goto choose;
+ }
+ close(fd);
+ if (ifr.ifr_mtu < ETHERMTU) {
+ fprintf(stderr, "interface %s mtu %d too low\n",
+ ifa->ifa_name, ifr.ifr_mtu);
+ freeifaddrs(ifap);
+ return (-1);
+ }
+ ifr.ifr_mtu -= 8;
+ if (rfc_4638_mtu > ifr.ifr_mtu) {
+ rfc_4638_mtu = ifr.ifr_mtu;
+ }
+ }
+
+choose:
bcopy(dl->sdl_data + dl->sdl_nlen, ea, sizeof(*ea));
strlcpy(ifnambuf, ifa->ifa_name, IFNAMSIZ);
freeifaddrs(ifap);
@@ -464,7 +500,7 @@ usage(void)
extern char *__progname;
fprintf(stderr,
- "usage: %s [-sv] [-i interface] [-n service] [-p system]\n",
+ "usage: %s [-sv] [-i interface] [-n service] [-p system] [-m
mtu]\n",
__progname);
}
Index: pppoe.h
===================================================================
RCS file: /cvs/src/usr.sbin/pppoe/pppoe.h,v
retrieving revision 1.9
diff -u -p -r1.9 pppoe.h
--- pppoe.h 4 Jul 2011 16:29:35 -0000 1.9
+++ pppoe.h 29 Jan 2012 13:59:41 -0000
@@ -1,4 +1,4 @@
-/* $OpenBSD: pppoe.h,v 1.9 2011/07/04 16:29:35 sthen Exp $ */
+/* $OpenBSD: pppoe.h,v 1.10 2011/10/15 02:05:07 yasuoka Exp $ */
/*
* Copyright (c) 2000 Network Security Technologies, Inc.
http://www.netsec.net
@@ -44,6 +44,8 @@ struct pppoe_header {
u_int16_t len; /* PPPoE payload length */
};
#define PPPOE_MTU (ETHERMTU - sizeof(struct pppoe_header))
+#define PPPOE_MTU_DIFF 2
+#define PPPOE_MIN_MTU (PPPOE_MTU - PPPOE_MTU_DIFF)
#define PPPOE_VER_S 0 /* Version shift */
#define PPPOE_VER_M 0x0f /* Version mask */
@@ -76,10 +78,12 @@ struct pppoe_tag {
#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_PPP_MAX_PAYLOAD 0x0120 /* RFC 4638
PPP-Max-Payload */
#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 u_int16_t rfc_4638_mtu; /* maximum value of mtu */
extern int option_verbose;
extern u_char etherbroadcastaddr[];
@@ -110,7 +114,7 @@ struct pppoe_session {
struct ether_addr s_ea; /* remote ethernet mac */
u_int16_t s_id; /* session id */
int s_fd; /* ttyfd */
- int s_first;
+ u_int16_t s_mtu; /* negotiated mtu */
};
struct pppoe_session_master {
Index: server.c
===================================================================
RCS file: /cvs/src/usr.sbin/pppoe/server.c,v
retrieving revision 1.13
diff -u -p -r1.13 server.c
--- server.c 3 Sep 2007 14:26:54 -0000 1.13
+++ server.c 29 Jan 2012 13:59:41 -0000
@@ -1,4 +1,4 @@
-/* $OpenBSD: server.c,v 1.13 2007/09/03 14:26:54 deraadt Exp $ */
+/* $OpenBSD: server.c,v 1.15 2011/11/05 09:20:36 yasuoka Exp $ */
/*
* Copyright (c) 2000 Network Security Technologies, Inc.
http://www.netsec.net
@@ -25,12 +25,9 @@
* 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>
@@ -38,11 +35,9 @@
#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>
@@ -65,13 +60,17 @@ static void recv_padt(int, struct ether_
struct ether_header *, struct pppoe_header *, u_long, u_int8_t *);
static void send_pado(int, struct ether_addr *,
- struct ether_header *, struct pppoe_header *, u_long, u_int8_t *);
+ struct ether_header *, struct pppoe_header *, u_long, u_int8_t *,
+ u_int16_t);
static void send_pads(int, u_int8_t *, struct ether_addr *,
- struct ether_header *, struct pppoe_header *, u_long, u_int8_t *);
+ struct ether_header *, struct pppoe_header *, u_long, u_int8_t *,
+ u_int16_t);
static void key_gen(void);
static u_int8_t *key_make(u_int8_t *, int, u_int8_t *, int);
static int key_cmp(u_int8_t *, int, u_int8_t *, int, u_int8_t *, int);
+static u_long scrub_pkt(u_long, u_int8_t *);
+
void
server_mode(int bpffd, u_int8_t *sysname, u_int8_t *srvname,
struct ether_addr *ea)
@@ -112,7 +111,7 @@ server_mode(int bpffd, u_int8_t *sysname
if (errno == EINTR)
continue;
err(EX_IOERR, "select");
- break;
+ /* NOTREACHED */
}
if (n == 0)
continue;
@@ -278,6 +277,8 @@ recv_padi(int bpffd, struct ether_addr *
struct pppoe_header *ph, u_long pktlen, u_int8_t *pktbuf)
{
struct tag_list tl;
+ struct tag_node *n;
+ u_int16_t mtu = 0;
if (ph->sessionid != 0)
return;
@@ -291,7 +292,17 @@ recv_padi(int bpffd, struct ether_addr *
if (tag_lookup(&tl, PPPOE_TAG_SERVICE_NAME, 1) != NULL)
goto out;
- send_pado(bpffd, ea, eh, ph, pktlen, pktbuf);
+ n = tag_lookup(&tl, PPPOE_TAG_PPP_MAX_PAYLOAD, 0);
+ if (n != NULL && n->len == sizeof(mtu)) {
+ mtu = n->val[1] | (n->val[0] << 8);
+ if (mtu < PPPOE_MIN_MTU) {
+ mtu = PPPOE_MIN_MTU;
+ } else if (mtu > rfc_4638_mtu) {
+ mtu = rfc_4638_mtu;
+ }
+ }
+
+ send_pado(bpffd, ea, eh, ph, pktlen, pktbuf, mtu);
out:
tag_destroy(&tl);
@@ -299,12 +310,15 @@ out:
static void
send_pado(int bpffd, struct ether_addr *ea, struct ether_header *eh,
- struct pppoe_header *ph, u_long pktlen, u_int8_t *pktbuf)
+ struct pppoe_header *ph, u_long pktlen, u_int8_t *pktbuf,
+ u_int16_t offer_mtu)
{
- struct pppoe_tag ktag, htag;
+ struct pppoe_tag ktag, htag, tmaxpayload, teol;
+ u_int16_t maxpayload;
+ u_long newlen;
u_int8_t hn[MAXHOSTNAMELEN];
u_int8_t *k = NULL;
- struct iovec v[7];
+ struct iovec v[10];
int idx = 0;
memcpy(&eh->ether_dhost[0], &eh->ether_shost[0], ETHER_ADDR_LEN);
@@ -315,7 +329,13 @@ send_pado(int bpffd, struct ether_addr *
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++;
+ /* Scrub unknown tags from the packet before returning them */
+ if ((newlen = scrub_pkt(pktlen, pktbuf)) == 0)
+ return;
+ if (newlen != pktlen)
+ ph->len -= pktlen - newlen;
+
+ v[idx].iov_base = pktbuf; v[idx].iov_len = newlen; idx++;
if (gethostname((char *)hn, sizeof(hn)) < 0)
return;
@@ -343,6 +363,28 @@ send_pado(int bpffd, struct ether_addr *
ph->len += sizeof(ktag.len) + sizeof(ktag.type) + COOKIE_LEN;
ktag.len = htons(COOKIE_LEN);
+ if (offer_mtu > 0) {
+ tmaxpayload.type = htons(PPPOE_TAG_PPP_MAX_PAYLOAD);
+ tmaxpayload.len = sizeof(maxpayload);
+ tmaxpayload.val = (u_int8_t*) &maxpayload;
+ maxpayload = htons(offer_mtu);
+ v[idx].iov_base = &tmaxpayload;
+ v[idx].iov_len = sizeof(tmaxpayload.len) +
sizeof(tmaxpayload.type);
+ idx++;
+ v[idx].iov_base = &maxpayload;
+ v[idx].iov_len = sizeof(maxpayload);
+ idx++;
+ ph->len += sizeof(tmaxpayload.len) +
sizeof(tmaxpayload.type) + sizeof(maxpayload);
+ tmaxpayload.len = htons(tmaxpayload.len);
+ }
+
+ teol.type = htons(PPPOE_TAG_END_OF_LIST);
+ teol.len = 0;
+ v[idx].iov_base = &teol;
+ v[idx].iov_len = sizeof(teol.type) + sizeof(teol.len);
+ ph->len += v[idx].iov_len;
+ idx++;
+
ph->len = htons(ph->len);
writev(bpffd, v, idx);
@@ -358,6 +400,7 @@ recv_padr(int bpffd, u_int8_t *sysname,
{
struct tag_list tl;
struct tag_node *n;
+ u_int16_t mtu = 0;
if (ph->sessionid != 0)
return;
@@ -373,7 +416,16 @@ recv_padr(int bpffd, u_int8_t *sysname,
ac_cookie_key, sizeof(ac_cookie_key)))
return;
- send_pads(bpffd, sysname, ea, eh, ph, pktlen, pktbuf);
+ n = tag_lookup(&tl, PPPOE_TAG_PPP_MAX_PAYLOAD, 0);
+ if (n != NULL && n->len == sizeof(mtu)) {
+ mtu = n->val[1] | (n->val[0] << 8);
+ if (mtu > rfc_4638_mtu || mtu < PPPOE_MIN_MTU) {
+ /* error; fallback */
+ mtu = PPPOE_MIN_MTU;
+ }
+ }
+
+ send_pads(bpffd, sysname, ea, eh, ph, pktlen, pktbuf, mtu);
tag_destroy(&tl);
}
@@ -381,12 +433,14 @@ recv_padr(int bpffd, u_int8_t *sysname,
static void
send_pads(int bpffd, u_int8_t *sysname, struct ether_addr *ea,
struct ether_header *eh, struct pppoe_header *ph,
- u_long pktlen, u_int8_t *pktbuf)
+ u_long pktlen, u_int8_t *pktbuf, u_int16_t final_mtu)
{
+ u_long newlen;
u_int8_t hn[MAXHOSTNAMELEN];
- struct iovec v[16];
+ u_int16_t maxpayload;
+ struct iovec v[19];
struct pppoe_session *s;
- struct pppoe_tag htag;
+ struct pppoe_tag htag, tmaxpayload, teol;
int idx = 0;
s = session_new((struct ether_addr *)&eh->ether_shost[0]);
@@ -404,7 +458,13 @@ send_pads(int bpffd, u_int8_t *sysname,
return;
v[idx].iov_base = ph; v[idx].iov_len = sizeof(*ph); idx++;
- v[idx].iov_base = pktbuf; v[idx].iov_len = pktlen; idx++;
+ /* Scrub unknown tags from the packet before returning them */
+ if ((newlen = scrub_pkt(pktlen, pktbuf)) == 0)
+ return;
+ if (newlen != pktlen)
+ ph->len -= pktlen - newlen;
+
+ v[idx].iov_base = pktbuf; v[idx].iov_len = newlen; idx++;
htag.len = strlen((char *)hn);
htag.type = htons(PPPOE_TAG_AC_NAME);
@@ -416,6 +476,29 @@ send_pads(int bpffd, u_int8_t *sysname,
ph->len += sizeof(htag.len) + sizeof(htag.type) + htag.len;
htag.len = htons(htag.len);
+ if (final_mtu > 0) {
+ s->s_mtu = final_mtu;
+ tmaxpayload.type = htons(PPPOE_TAG_PPP_MAX_PAYLOAD);
+ tmaxpayload.len = sizeof(maxpayload);
+ tmaxpayload.val = (u_int8_t*) &maxpayload;
+ maxpayload = htons(final_mtu);
+ v[idx].iov_base = &tmaxpayload;
+ v[idx].iov_len = sizeof(tmaxpayload.len) +
sizeof(tmaxpayload.type);
+ idx++;
+ v[idx].iov_base = &maxpayload;
+ v[idx].iov_len = sizeof(maxpayload);
+ idx++;
+ ph->len += sizeof(tmaxpayload.len) +
sizeof(tmaxpayload.type) + sizeof(maxpayload);
+ tmaxpayload.len = htons(tmaxpayload.len);
+ }
+
+ teol.type = htons(PPPOE_TAG_END_OF_LIST);
+ teol.len = 0;
+ v[idx].iov_base = &teol;
+ v[idx].iov_len = sizeof(teol.type) + sizeof(teol.len);
+ ph->len += v[idx].iov_len;
+ idx++;
+
ph->len = htons(ph->len);
writev(bpffd, v, idx);
@@ -446,4 +529,62 @@ recv_padt(int bpffd, struct ether_addr *
out:
tag_destroy(&tl);
+}
+
+static u_long
+scrub_pkt(u_long pktlen, u_int8_t *pkt)
+{
+ u_long newlen = 0;
+ u_int16_t ttype, tlen;
+ u_int8_t *p = pkt;
+
+ 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;
+
+ pkt += tlen;
+ pktlen -= tlen;
+
+ switch (ttype) {
+
+ /* Echo these tags back to the client */
+ case PPPOE_TAG_SERVICE_NAME:
+ case PPPOE_TAG_AC_NAME:
+ case PPPOE_TAG_HOST_UNIQ:
+ case PPPOE_TAG_AC_COOKIE:
+ case PPPOE_TAG_VENDOR_SPEC:
+ case PPPOE_TAG_RELAY_SESSION:
+ case PPPOE_TAG_SERVICE_NAME_ERROR:
+ case PPPOE_TAG_AC_SYSTEM_ERROR:
+ case PPPOE_TAG_GENERIC_ERROR:
+ p = pkt;
+ newlen += sizeof(u_int16_t) + sizeof(u_int16_t) + tlen;
+ break;
+
+ /* Scrub these */
+ case PPPOE_TAG_END_OF_LIST:
+ case PPPOE_TAG_PPP_MAX_PAYLOAD:
+ default:
+ if (pktlen != 0)
+ bcopy(pkt, p, pktlen);
+ pkt = p;
+ break;
+ }
+ }
+
+ if (pktlen != 0)
+ return (0);
+ return (newlen);
}
Index: session.c
===================================================================
RCS file: /cvs/src/usr.sbin/pppoe/session.c,v
retrieving revision 1.3
diff -u -p -r1.3 session.c
--- session.c 6 May 2004 20:29:04 -0000 1.3
+++ session.c 29 Jan 2012 13:59:41 -0000
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.3 2004/05/06 20:29:04 deraadt Exp $ */
+/* $OpenBSD: session.c,v 1.5 2011/11/05 09:20:36 yasuoka Exp $ */
/*
* Copyright (c) 2000 Network Security Technologies, Inc.
http://www.netsec.net
@@ -25,24 +25,15 @@
* 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"
@@ -91,8 +82,8 @@ session_new(struct ether_addr *ea)
s->s_id = id;
s->s_fd = -1;
- s->s_first = 1;
memcpy(&s->s_ea, ea, ETHER_ADDR_LEN);
+ s->s_mtu = PPPOE_MIN_MTU;
LIST_INSERT_HEAD(&session_master.sm_sessions, s, s_next);
return (s);
Index: tag.c
===================================================================
RCS file: /cvs/src/usr.sbin/pppoe/tag.c,v
retrieving revision 1.4
diff -u -p -r1.4 tag.c
--- tag.c 4 Jul 2011 16:29:35 -0000 1.4
+++ tag.c 29 Jan 2012 13:59:41 -0000
@@ -1,4 +1,4 @@
-/* $OpenBSD: tag.c,v 1.4 2011/07/04 16:29:35 sthen Exp $ */
+/* $OpenBSD: tag.c,v 1.5 2011/11/05 09:20:36 yasuoka Exp $ */
/*
* Copyright (c) 2000 Network Security Technologies, Inc.
http://www.netsec.net
@@ -25,24 +25,14 @@
* 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"