On 2012/01/31 23:53, Ben Gould wrote:
> I couldn't get the pppoe server to work on -current, rebuilt -current
> yesterday and it now works - user error.
>
> The following works in all the combinations 5.0 client/server
> userland and with -current client/server and with -current pppoe(4).
>
> -- ben
fixed diff (linewrapping and some spaces->tabs and 80-column
formatting in the diff itself), otherwise untested so far.
Index: client.c
===================================================================
RCS file: /cvs/src/usr.sbin/pppoe/client.c,v
retrieving revision 1.24
diff -u -p -r1.24 client.c
--- client.c 5 Nov 2011 09:20:36 -0000 1.24
+++ client.c 1 Feb 2012 02:34:04 -0000
@@ -50,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 *,
@@ -80,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)
@@ -144,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 */
@@ -190,6 +193,22 @@ 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;
@@ -202,9 +221,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;
@@ -245,6 +265,19 @@ 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;
@@ -407,6 +440,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) {
@@ -462,6 +507,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.13
diff -u -p -r1.13 common.c
--- common.c 5 Nov 2011 09:20:36 -0000 1.13
+++ common.c 1 Feb 2012 02:34:04 -0000
@@ -138,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);
}
@@ -146,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 1 Feb 2012 02:34:04 -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 1 Feb 2012 02:34:04 -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.19
diff -u -p -r1.19 pppoe.c
--- pppoe.c 5 Nov 2011 09:20:36 -0000 1.19
+++ pppoe.c 1 Feb 2012 02:34:04 -0000
@@ -46,9 +46,11 @@
#include <sysexits.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 };
@@ -72,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) {
@@ -91,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();
@@ -412,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");
@@ -442,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);
@@ -461,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.10
diff -u -p -r1.10 pppoe.h
--- pppoe.h 15 Oct 2011 02:05:07 -0000 1.10
+++ pppoe.h 1 Feb 2012 02:34:04 -0000
@@ -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,6 +114,7 @@ struct pppoe_session {
struct ether_addr s_ea; /* remote ethernet mac */
u_int16_t s_id; /* session id */
int s_fd; /* ttyfd */
+ 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.15
diff -u -p -r1.15 server.c
--- server.c 5 Nov 2011 09:20:36 -0000 1.15
+++ server.c 1 Feb 2012 02:34:04 -0000
@@ -60,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)
@@ -273,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;
@@ -286,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);
@@ -294,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);
@@ -310,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;
@@ -338,6 +363,30 @@ 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);
@@ -353,6 +402,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;
@@ -368,7 +418,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);
}
@@ -376,12 +435,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]);
@@ -399,7 +460,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);
@@ -411,6 +478,31 @@ 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);
@@ -441,4 +533,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.5
diff -u -p -r1.5 session.c
--- session.c 5 Nov 2011 09:20:36 -0000 1.5
+++ session.c 1 Feb 2012 02:34:04 -0000
@@ -83,6 +83,7 @@ session_new(struct ether_addr *ea)
s->s_id = id;
s->s_fd = -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);