From leo@v.gz.ru  Tue Feb  4 14:32:35 2003
Return-Path: <leo@v.gz.ru>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id 6E96837B401
	for <FreeBSD-gnats-submit@freebsd.org>; Tue,  4 Feb 2003 14:32:35 -0800 (PST)
Received: from v.gz.ru (v.gz.ru [194.67.72.3])
	by mx1.FreeBSD.org (Postfix) with ESMTP id ABB8943F9B
	for <FreeBSD-gnats-submit@freebsd.org>; Tue,  4 Feb 2003 14:32:28 -0800 (PST)
	(envelope-from leo@v.gz.ru)
Received: from virgin.v.gz.ru (localhost [127.0.0.1])
	by v.gz.ru (8.12.6/8.12.6) with ESMTP id h14MWMLG005761
	(version=TLSv1/SSLv3 cipher=EDH-RSA-DES-CBC3-SHA bits=168 verify=NO);
	Wed, 5 Feb 2003 01:32:22 +0300 (MSK)
	(envelope-from leo@virgin.v.gz.ru)
Received: (from leo@localhost)
	by virgin.v.gz.ru (8.12.6/8.12.5/Submit) id h14MWLGj005760;
	Wed, 5 Feb 2003 01:32:21 +0300 (MSK)
Message-Id: <200302042232.h14MWLGj005760@virgin.v.gz.ru>
Date: Wed, 5 Feb 2003 01:32:21 +0300 (MSK)
From: Lev Shamardin <leo@v.gz.ru>
Reply-To: Lev Shamardin <shamardin@theory.sinp.msu.ru>
To: FreeBSD-gnats-submit@freebsd.org
Cc: Dmitro Dudenko <dudenko@tak.estra.ru>
Subject: if ng_pppoe switches to nonstandard mode it stays in it forever
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         47920
>Category:       kern
>Synopsis:       if ng_pppoe switches to nonstandard mode it stays in it forever
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    yar
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Tue Feb 04 14:40:06 PST 2003
>Closed-Date:    Mon Dec 29 06:42:54 PST 2003
>Last-Modified:  Mon Dec 29 06:42:54 PST 2003
>Originator:     Lev Shamardin
>Release:        FreeBSD 4.7-STABLE i386
>Organization:
MSU Hostel Network
>Environment:
System: FreeBSD virgin.v.gz.ru 4.7-STABLE FreeBSD 4.7-STABLE #2: Sat Dec 14 21:39:44 MSK 2002 glebius@morannon.v.ru:/usr/obj/usr/src/sys/HYMEN i386
>Description:
If the sys/netgraph/ng_pppoe.c switches to non-standard mode, it remains
in non-standard forever. The only known software PPPoE client supporting 
non-standard mode is in FreeBSD.

If the network contains FreeBSD PPPoE service provider, and at least one
FreeBDF PPPoE client, one accidental switch to the non-standard mode will
cause inoperability of the whole PPPoE network, because the only way to
switch pppoe back to standard mode is to reboot the kernel, and if the
FreeBSD client reconnects to the server, this will bring the server back to
non-standard mode.

In our network we have many Windows XP and Efficient Networks EnterNet
PPPoE clients and some FreeBSD clients. Due to some accident our PPPoE server 
switched to the non-standard PPPoE mode. And after this we've got a loop:
if we reboot the server, one of the FreeBSD clients reconnects in 
non-standard mode turning the server back to non-standard mode. We had 
to reboot all FreeBSD nodes in our network simultaneously to make the 
system operational again, but there is no guarantee that this will not 
happen again.

>How-To-Repeat:
Generate a PPPoE Discovery packet with 0x3c12 protocol in ethernet header
instead of 0x8863 and send it to a server running pppoed.

>Fix:
There should be a kernel option or sysctl variable which can disable usage
of non-standard pppoe mode.

>Release-Note:
>Audit-Trail:

From: Gleb Smirnoff <glebius@cell.sick.ru>
To: Lev Shamardin <shamardin@theory.sinp.msu.ru>
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: kern/47920: if ng_pppoe switches to nonstandard mode it stays in it forever
Date: Mon, 10 Feb 2003 16:16:08 +0300

 Hi!
 
 A workaround and fix of the problem follows.
 
 L> cause inoperability of the whole PPPoE network, because the only way to
 L> switch pppoe back to standard mode is to reboot the kernel, and if the
 L> FreeBSD client reconnects to the server, this will bring the server back to
 L> non-standard mode.
 
 Really you do not need to reboot, but you can switch it back using:
 sysctl net.graph.nonstandard_pppoe=0
 
 But it will remain in standard mode until next stupid packet in the network.
 The dirty workaround we used is running this command in cron(8).
 
 L> >Fix:
 L> There should be a kernel option or sysctl variable which can disable usage
 L> of non-standard pppoe mode.
 
 Here is the patch we are using now. It is not tested thoroughly because I
 don't know where does non-standard packets come from, and I do not generated
 them for testing purposes. But this should work.
 
 The oid net.graph.nonstandard_pppoe gets new value of -1, which means
 "stay standard forever!".
 
 --- ng_pppoe.c.orig	Mon Feb 10 15:16:04 2003
 +++ ng_pppoe.c	Mon Feb 10 15:41:40 2003
 @@ -166,7 +166,6 @@
  	 ETHERTYPE_PPPOE_DISC};
  
  static int nonstandard;
 -static int
  ngpppoe_set_ethertype(SYSCTL_HANDLER_ARGS)
  {
  	int error;
 @@ -176,12 +175,19 @@
  	error = sysctl_handle_int(oidp, &val, sizeof(int), req);
  	if (error != 0 || req->newptr == NULL)
  		return (error);
 -	if (val == 1) {
 +	switch (val) {
 +	case 1:
  		nonstandard = 1;
  		eh_prototype.ether_type = ETHERTYPE_PPPOE_STUPID_DISC;
 -	} else {
 +		break;
 +	case 0:
  		nonstandard = 0;
  		eh_prototype.ether_type = ETHERTYPE_PPPOE_DISC;
 +		break;
 +	case -1:
 +		nonstandard = -1;
 +		eh_prototype.ether_type = ETHERTYPE_PPPOE_DISC;
 +		break;
  	}
  	return (0);
  }
 @@ -913,8 +919,10 @@
  		code = wh->ph.code; 
  		switch(wh->eh.ether_type) {
  		case	ETHERTYPE_PPPOE_STUPID_DISC:
 -			nonstandard = 1;
 -			eh_prototype.ether_type = ETHERTYPE_PPPOE_STUPID_DISC;
 +			if (nonstandard > -1) {
 +			  nonstandard = 1;
 +			  eh_prototype.ether_type = ETHERTYPE_PPPOE_STUPID_DISC;
 +			}
  			/* fall through */
  		case	ETHERTYPE_PPPOE_DISC:
  			/*
 
 -- 
 Totus tuus, Glebius.
 GLEBIUS-RIPN GLEB-RIPE

From: Gleb Smirnoff <glebius@cell.sick.ru>
To: freebsd-bugs@FreeBSD.ORG, FreeBSD-gnats-submit@FreeBSD.ORG
Cc:  
Subject: Re: kern/47920: if ng_pppoe switches to nonstandard mode it stays in it forever
Date: Mon, 10 Feb 2003 20:29:59 +0300

 Sorry. This one is better.
 
 -- 
 Totus tuus, Glebius.
 GLEBIUS-RIPN GLEB-RIPE
 
 --- ng_pppoe.c.orig	Mon Feb 10 15:16:04 2003
 +++ ng_pppoe.c	Mon Feb 10 20:27:34 2003
 @@ -166,6 +166,9 @@
  	 ETHERTYPE_PPPOE_DISC};
  
  static int nonstandard;
 +#define PPPOE_STANDARD		0	/* try standard */
 +#define PPPOE_NONSTANDARD	1	/* be nonstandard */
 +#define PPPOE_KEEPSTANDARD	-1	/* never switch to nonstandard mode */
  static int
  ngpppoe_set_ethertype(SYSCTL_HANDLER_ARGS)
  {
 @@ -176,12 +179,19 @@
  	error = sysctl_handle_int(oidp, &val, sizeof(int), req);
  	if (error != 0 || req->newptr == NULL)
  		return (error);
 -	if (val == 1) {
 -		nonstandard = 1;
 +	switch (val) {
 +	case PPPOE_NONSTANDARD:
 +		nonstandard = PPPOE_NONSTANDARD;
  		eh_prototype.ether_type = ETHERTYPE_PPPOE_STUPID_DISC;
 -	} else {
 -		nonstandard = 0;
 +		break;
 +	case PPPOE_STANDARD:
 +		nonstandard = PPPOE_STANDARD;
  		eh_prototype.ether_type = ETHERTYPE_PPPOE_DISC;
 +		break;
 +	case PPPOE_KEEPSTANDARD:
 +		nonstandard = PPPOE_KEEPSTANDARD;
 +		eh_prototype.ether_type = ETHERTYPE_PPPOE_DISC;
 +		break;
  	}
  	return (0);
  }
 @@ -913,8 +923,12 @@
  		code = wh->ph.code; 
  		switch(wh->eh.ether_type) {
  		case	ETHERTYPE_PPPOE_STUPID_DISC:
 -			nonstandard = 1;
 -			eh_prototype.ether_type = ETHERTYPE_PPPOE_STUPID_DISC;
 +			if (nonstandard > PPPOE_KEEPSTANDARD) {
 +			  nonstandard = PPPOE_NONSTANDARD;
 +			  eh_prototype.ether_type = ETHERTYPE_PPPOE_STUPID_DISC;
 +			  printf("Switched to nonstandard PPPoE");
 +			} else
 +			  printf("Ignored nonstandard PPPoE");
  			/* fall through */
  		case	ETHERTYPE_PPPOE_DISC:
  			/*
 @@ -1098,7 +1112,7 @@
  				 * from NEWCONNECTED to CONNECTED
  				 */
  				sp->pkt_hdr = neg->pkt->pkt_header;
 -				if (nonstandard)
 +				if (nonstandard == PPPOE_NONSTANDARD)
  					sp->pkt_hdr.eh.ether_type
  						= ETHERTYPE_PPPOE_STUPID_SESS;
  				else
 @@ -1150,7 +1164,7 @@
  				 * Keep a copy of the header we will be using.
  				 */
  				sp->pkt_hdr = neg->pkt->pkt_header;
 -				if (nonstandard)
 +				if (nonstandard == PPPOE_NONSTANDARD)
  					sp->pkt_hdr.eh.ether_type
  						= ETHERTYPE_PPPOE_STUPID_SESS;
  				else
 @@ -1434,7 +1448,7 @@
  			/* revert the stored header to DISC/PADT mode */
  		 	wh = &sp->pkt_hdr;
  			wh->ph.code = PADT_CODE;
 -			if (nonstandard)
 +			if (nonstandard == PPPOE_NONSTANDARD)
  				wh->eh.ether_type = ETHERTYPE_PPPOE_STUPID_DISC;
  			else
  				wh->eh.ether_type = ETHERTYPE_PPPOE_DISC;

From: Gleb Smirnoff <glebius@cell.sick.ru>
To: freebsd-bugs@FreeBSD.ORG, FreeBSD-gnats-submit@FreeBSD.ORG
Cc:  
Subject: Re: kern/47920: if ng_pppoe switches to nonstandard mode it stays in it forever
Date: Wed, 12 Feb 2003 17:43:37 +0300

  This one is even better. It logs source MAC address of nonstandard packet.
 
 -- 
 Totus tuus, Glebius.
 GLEBIUS-RIPN GLEB-RIPE
 
 
 --- ng_pppoe.c.orig	Mon Feb 10 15:16:04 2003
 +++ ng_pppoe.c	Wed Feb 12 17:21:20 2003
 @@ -54,6 +54,7 @@
  #include <sys/malloc.h>
  #include <sys/errno.h>
  #include <sys/sysctl.h>
 +#include <sys/syslog.h>
  #include <net/ethernet.h>
  
  #include <netgraph/ng_message.h>
 @@ -166,6 +167,9 @@
  	 ETHERTYPE_PPPOE_DISC};
  
  static int nonstandard;
 +#define PPPOE_STANDARD		0	/* try standard */
 +#define PPPOE_NONSTANDARD	1	/* be nonstandard */
 +#define PPPOE_KEEPSTANDARD	-1	/* never switch to nonstandard mode */
  static int
  ngpppoe_set_ethertype(SYSCTL_HANDLER_ARGS)
  {
 @@ -176,12 +180,19 @@
  	error = sysctl_handle_int(oidp, &val, sizeof(int), req);
  	if (error != 0 || req->newptr == NULL)
  		return (error);
 -	if (val == 1) {
 -		nonstandard = 1;
 +	switch (val) {
 +	case PPPOE_NONSTANDARD:
 +		nonstandard = PPPOE_NONSTANDARD;
  		eh_prototype.ether_type = ETHERTYPE_PPPOE_STUPID_DISC;
 -	} else {
 -		nonstandard = 0;
 +		break;
 +	case PPPOE_STANDARD:
 +		nonstandard = PPPOE_STANDARD;
  		eh_prototype.ether_type = ETHERTYPE_PPPOE_DISC;
 +		break;
 +	case PPPOE_KEEPSTANDARD:
 +		nonstandard = PPPOE_KEEPSTANDARD;
 +		eh_prototype.ether_type = ETHERTYPE_PPPOE_DISC;
 +		break;
  	}
  	return (0);
  }
 @@ -913,8 +924,16 @@
  		code = wh->ph.code; 
  		switch(wh->eh.ether_type) {
  		case	ETHERTYPE_PPPOE_STUPID_DISC:
 -			nonstandard = 1;
 -			eh_prototype.ether_type = ETHERTYPE_PPPOE_STUPID_DISC;
 +			if (nonstandard > PPPOE_KEEPSTANDARD) {
 +			  nonstandard = PPPOE_NONSTANDARD;
 +			  eh_prototype.ether_type = ETHERTYPE_PPPOE_STUPID_DISC;
 +			  log(LOG_NOTICE,
 +				"Switched to nonstandard PPPoE (packet from %*D)\n",
 +				sizeof(wh->eh.ether_shost), wh->eh.ether_shost,":");
 +			} else
 +			  log(LOG_NOTICE,
 +				"Ignored nonstandard PPPoE packet from %*D\n",
 +				sizeof(wh->eh.ether_shost), wh->eh.ether_shost,":");
  			/* fall through */
  		case	ETHERTYPE_PPPOE_DISC:
  			/*
 @@ -1098,7 +1117,7 @@
  				 * from NEWCONNECTED to CONNECTED
  				 */
  				sp->pkt_hdr = neg->pkt->pkt_header;
 -				if (nonstandard)
 +				if (nonstandard == PPPOE_NONSTANDARD)
  					sp->pkt_hdr.eh.ether_type
  						= ETHERTYPE_PPPOE_STUPID_SESS;
  				else
 @@ -1150,7 +1169,7 @@
  				 * Keep a copy of the header we will be using.
  				 */
  				sp->pkt_hdr = neg->pkt->pkt_header;
 -				if (nonstandard)
 +				if (nonstandard == PPPOE_NONSTANDARD)
  					sp->pkt_hdr.eh.ether_type
  						= ETHERTYPE_PPPOE_STUPID_SESS;
  				else
 @@ -1434,7 +1453,7 @@
  			/* revert the stored header to DISC/PADT mode */
  		 	wh = &sp->pkt_hdr;
  			wh->ph.code = PADT_CODE;
 -			if (nonstandard)
 +			if (nonstandard == PPPOE_NONSTANDARD)
  				wh->eh.ether_type = ETHERTYPE_PPPOE_STUPID_DISC;
  			else
  				wh->eh.ether_type = ETHERTYPE_PPPOE_DISC;

From: Yar Tikhiy <yar@FreeBSD.ORG>
To: Gleb Smirnoff <glebius@cell.sick.ru>,
	FreeBSD-gnats-submit@FreeBSD.ORG, freebsd-bugs@FreeBSD.ORG
Cc:  
Subject: Re: kern/47920: if ng_pppoe switches to nonstandard mode it stays in it forever
Date: Tue, 9 Dec 2003 16:14:41 +0300

 I would rather change the name of the variable "nonstandard"
 to "pppoe_mode", not "standard", because lines like this one:
 
 	standard = PPPOE_NONSTANDARD;
 
 give me a schizoid feeling :-)
 
 I also believe you should not omit the "freebsd-gnats-submit@freebsd.org"
 address from the list of recipients when sending a follow-up to a PR, or
 else GNATS will not be able to add your follow-up to the audit trail.
 
 -- 
 Yar

From: Gleb Smirnoff <glebius@cell.sick.ru>
To: Yar Tikhiy <yar@FreeBSD.ORG>
Cc: FreeBSD-gnats-submit@FreeBSD.ORG, freebsd-bugs@FreeBSD.ORG
Subject: Re: kern/47920: if ng_pppoe switches to nonstandard mode it stays in it forever
Date: Tue, 9 Dec 2003 18:20:54 +0300

 --dDRMvlgZJXvWKvBx
 Content-Type: text/plain; charset=koi8-r
 Content-Disposition: inline
 
 On Tue, Dec 09, 2003 at 04:14:41PM +0300, Yar Tikhiy wrote:
 Y> I would rather change the name of the variable "nonstandard"
 Y> to "pppoe_mode", not "standard", because lines like this one:
 Y> 
 Y> 	standard = PPPOE_NONSTANDARD;
 Y> 
 Y> give me a schizoid feeling :-)
 
 Here it is.
 
 -- 
 Totus tuus, Glebius.
 GLEBIUS-RIPN GLEB-RIPE
 
 --dDRMvlgZJXvWKvBx
 Content-Type: text/plain; charset=koi8-r
 Content-Disposition: attachment; filename="ng_pppoe.c.diff"
 
 --- /usr/src/sys/netgraph/ng_pppoe.c	Wed Jul  3 02:17:18 2002
 +++ ng_pppoe.c	Tue Dec  9 11:57:25 2003
 @@ -54,6 +54,7 @@
  #include <sys/malloc.h>
  #include <sys/errno.h>
  #include <sys/sysctl.h>
 +#include <sys/syslog.h>
  #include <net/ethernet.h>
  
  #include <netgraph/ng_message.h>
 @@ -165,23 +166,33 @@
  	 {0x00,0x00,0x00,0x00,0x00,0x00},
  	 ETHERTYPE_PPPOE_DISC};
  
 -static int nonstandard;
 +static int pppoe_mode;
 +#define PPPOE_STANDARD		0	/* try standard */
 +#define PPPOE_NONSTANDARD	1	/* be nonstandard */
 +#define PPPOE_KEEPSTANDARD	-1	/* never switch to nonstandard mode */
  static int
  ngpppoe_set_ethertype(SYSCTL_HANDLER_ARGS)
  {
  	int error;
  	int val;
  
 -	val = nonstandard;
 +	val = pppoe_mode;
  	error = sysctl_handle_int(oidp, &val, sizeof(int), req);
  	if (error != 0 || req->newptr == NULL)
  		return (error);
 -	if (val == 1) {
 -		nonstandard = 1;
 +	switch (val) {
 +	case PPPOE_NONSTANDARD:
 +		pppoe_mode = PPPOE_NONSTANDARD;
  		eh_prototype.ether_type = ETHERTYPE_PPPOE_STUPID_DISC;
 -	} else {
 -		nonstandard = 0;
 +		break;
 +	case PPPOE_STANDARD:
 +		pppoe_mode = PPPOE_STANDARD;
  		eh_prototype.ether_type = ETHERTYPE_PPPOE_DISC;
 +		break;
 +	case PPPOE_KEEPSTANDARD:
 +		pppoe_mode = PPPOE_KEEPSTANDARD;
 +		eh_prototype.ether_type = ETHERTYPE_PPPOE_DISC;
 +		break;
  	}
  	return (0);
  }
 @@ -913,8 +924,16 @@
  		code = wh->ph.code; 
  		switch(wh->eh.ether_type) {
  		case	ETHERTYPE_PPPOE_STUPID_DISC:
 -			nonstandard = 1;
 -			eh_prototype.ether_type = ETHERTYPE_PPPOE_STUPID_DISC;
 +			if (pppoe_mode != PPPOE_KEEPSTANDARD) {
 +			  pppoe_mode = PPPOE_NONSTANDARD;
 +			  eh_prototype.ether_type = ETHERTYPE_PPPOE_STUPID_DISC;
 +			  log(LOG_NOTICE,
 +				"Switched to nonstandard PPPoE (packet from %*D)\n",
 +				sizeof(wh->eh.ether_shost), wh->eh.ether_shost,":");
 +			} else
 +			  log(LOG_NOTICE,
 +				"Ignored nonstandard PPPoE packet from %*D\n",
 +				sizeof(wh->eh.ether_shost), wh->eh.ether_shost,":");
  			/* fall through */
  		case	ETHERTYPE_PPPOE_DISC:
  			/*
 @@ -1098,7 +1117,7 @@
  				 * from NEWCONNECTED to CONNECTED
  				 */
  				sp->pkt_hdr = neg->pkt->pkt_header;
 -				if (nonstandard)
 +				if (pppoe_mode == PPPOE_NONSTANDARD)
  					sp->pkt_hdr.eh.ether_type
  						= ETHERTYPE_PPPOE_STUPID_SESS;
  				else
 @@ -1150,7 +1169,7 @@
  				 * Keep a copy of the header we will be using.
  				 */
  				sp->pkt_hdr = neg->pkt->pkt_header;
 -				if (nonstandard)
 +				if (pppoe_mode == PPPOE_NONSTANDARD)
  					sp->pkt_hdr.eh.ether_type
  						= ETHERTYPE_PPPOE_STUPID_SESS;
  				else
 @@ -1434,7 +1453,7 @@
  			/* revert the stored header to DISC/PADT mode */
  		 	wh = &sp->pkt_hdr;
  			wh->ph.code = PADT_CODE;
 -			if (nonstandard)
 +			if (pppoe_mode == PPPOE_NONSTANDARD)
  				wh->eh.ether_type = ETHERTYPE_PPPOE_STUPID_DISC;
  			else
  				wh->eh.ether_type = ETHERTYPE_PPPOE_DISC;
 
 --dDRMvlgZJXvWKvBx--

From: Yar Tikhiy <yar@FreeBSD.ORG>
To: Gleb Smirnoff <glebius@cell.sick.ru>,
	FreeBSD-gnats-submit@FreeBSD.ORG
Cc:  
Subject: Re: kern/47920: if ng_pppoe switches to nonstandard mode it stays in it forever
Date: Wed, 17 Dec 2003 20:42:34 +0300

 On Tue, Dec 09, 2003 at 06:20:54PM +0300, Gleb Smirnoff wrote:
 > On Tue, Dec 09, 2003 at 04:14:41PM +0300, Yar Tikhiy wrote:
 > Y> I would rather change the name of the variable "nonstandard"
 > Y> to "pppoe_mode", not "standard", because lines like this one:
 > Y> 
 > Y> 	standard = PPPOE_NONSTANDARD;
 > Y> 
 > Y> give me a schizoid feeling :-)
 > 
 > Here it is.
 
 Would you mind testing the below version of your patch, revised.
 Please pay attention to its points:
 a) sanity check values passed through sysctl;
 b) avoid double setting nonstandard mode;
 c) format source according to style(9);
 d) initialize pppoe_mode for clarity since it's no longer
    just a boolean trigger.
 
 -- 
 Yar
 
 Index: ng_pppoe.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/netgraph/ng_pppoe.c,v
 retrieving revision 1.58
 diff -u -p -r1.58 ng_pppoe.c
 --- ng_pppoe.c	19 Feb 2003 05:47:31 -0000	1.58
 +++ ng_pppoe.c	17 Dec 2003 17:29:58 -0000
 @@ -54,6 +54,7 @@
  #include <sys/malloc.h>
  #include <sys/errno.h>
  #include <sys/sysctl.h>
 +#include <sys/syslog.h>
  #include <net/ethernet.h>
  
  #include <netgraph/ng_message.h>
 @@ -244,23 +245,36 @@ struct ether_header eh_prototype =
  	 {0x00,0x00,0x00,0x00,0x00,0x00},
  	 ETHERTYPE_PPPOE_DISC};
  
 -static int nonstandard;
 +#define PPPOE_KEEPSTANDARD	-1	/* never switch to nonstandard mode */
 +#define PPPOE_STANDARD		0	/* try standard mode (default) */
 +#define PPPOE_NONSTANDARD	1	/* just be in nonstandard mode */
 +static int pppoe_mode = PPPOE_STANDARD;
 +
  static int
  ngpppoe_set_ethertype(SYSCTL_HANDLER_ARGS)
  {
  	int error;
  	int val;
  
 -	val = nonstandard;
 +	val = pppoe_mode;
  	error = sysctl_handle_int(oidp, &val, sizeof(int), req);
  	if (error != 0 || req->newptr == NULL)
  		return (error);
 -	if (val == 1) {
 -		nonstandard = 1;
 +	switch (val) {
 +	case PPPOE_NONSTANDARD:
 +		pppoe_mode = PPPOE_NONSTANDARD;
  		eh_prototype.ether_type = ETHERTYPE_PPPOE_STUPID_DISC;
 -	} else {
 -		nonstandard = 0;
 +		break;
 +	case PPPOE_STANDARD:
 +		pppoe_mode = PPPOE_STANDARD;
  		eh_prototype.ether_type = ETHERTYPE_PPPOE_DISC;
 +		break;
 +	case PPPOE_KEEPSTANDARD:
 +		pppoe_mode = PPPOE_KEEPSTANDARD;
 +		eh_prototype.ether_type = ETHERTYPE_PPPOE_DISC;
 +		break;
 +	default:
 +		return (EINVAL);
  	}
  	return (0);
  }
 @@ -982,8 +996,21 @@ AAA
  		length = ntohs(wh->ph.length);
  		switch(wh->eh.ether_type) {
  		case	ETHERTYPE_PPPOE_STUPID_DISC:
 -			nonstandard = 1;
 -			eh_prototype.ether_type = ETHERTYPE_PPPOE_STUPID_DISC;
 +			if (pppoe_mode == PPPOE_STANDARD) {
 +				pppoe_mode = PPPOE_NONSTANDARD;
 +				eh_prototype.ether_type =
 +				    ETHERTYPE_PPPOE_STUPID_DISC;
 +				log(LOG_NOTICE,
 +				    "Switched to nonstandard PPPoE mode due to "
 +				    "packet from %*D\n",
 +				    sizeof(wh->eh.ether_shost),
 +				    wh->eh.ether_shost, ":");
 +			} else if (pppoe_mode == PPPOE_KEEPSTANDARD)
 +				log(LOG_NOTICE,
 +				    "Ignored nonstandard PPPoE packet "
 +				    "from %*D\n",
 +				    sizeof(wh->eh.ether_shost),
 +				    wh->eh.ether_shost, ":");
  			/* fall through */
  		case	ETHERTYPE_PPPOE_DISC:
  			/*
 @@ -1185,7 +1212,7 @@ AAA
  				 * from NEWCONNECTED to CONNECTED
  				 */
  				sp->pkt_hdr = neg->pkt->pkt_header;
 -				if (nonstandard)
 +				if (pppoe_mode == PPPOE_NONSTANDARD)
  					sp->pkt_hdr.eh.ether_type
  						= ETHERTYPE_PPPOE_STUPID_SESS;
  				else
 @@ -1237,7 +1264,7 @@ AAA
  				 * Keep a copy of the header we will be using.
  				 */
  				sp->pkt_hdr = neg->pkt->pkt_header;
 -				if (nonstandard)
 +				if (pppoe_mode == PPPOE_NONSTANDARD)
  					sp->pkt_hdr.eh.ether_type
  						= ETHERTYPE_PPPOE_STUPID_SESS;
  				else
 @@ -1519,7 +1546,7 @@ AAA
  			/* revert the stored header to DISC/PADT mode */
  		 	wh = &sp->pkt_hdr;
  			wh->ph.code = PADT_CODE;
 -			if (nonstandard)
 +			if (pppoe_mode == PPPOE_NONSTANDARD)
  				wh->eh.ether_type = ETHERTYPE_PPPOE_STUPID_DISC;
  			else
  				wh->eh.ether_type = ETHERTYPE_PPPOE_DISC;

From: Gleb Smirnoff <glebius@cell.sick.ru>
To: Yar Tikhiy <yar@FreeBSD.ORG>
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: kern/47920: if ng_pppoe switches to nonstandard mode it stays in it forever
Date: Thu, 18 Dec 2003 13:08:48 +0300

 On Wed, Dec 17, 2003 at 08:42:34PM +0300, Yar Tikhiy wrote:
 Y> Would you mind testing the below version of your patch, revised.
 Y> Please pay attention to its points:
 Y> a) sanity check values passed through sysctl;
 Y> b) avoid double setting nonstandard mode;
 Y> c) format source according to style(9);
 Y> d) initialize pppoe_mode for clarity since it's no longer
 Y>    just a boolean trigger.
 
 I have tested it on STABLE. It works OK. I have also asked PR's
 originator to test it.
 
 -- 
 Totus tuus, Glebius.
 GLEBIUS-RIPN GLEB-RIPE

From: Yar Tikhiy <yar@FreeBSD.ORG>
To: Gleb Smirnoff <glebius@cell.sick.ru>
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: kern/47920: if ng_pppoe switches to nonstandard mode it stays in it forever
Date: Thu, 18 Dec 2003 20:22:04 +0300

 Mime-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 In-Reply-To: <20031218100848.GA67923@cell.sick.ru>
 User-Agent: Mutt/1.5.3i
 
 On Thu, Dec 18, 2003 at 01:08:48PM +0300, Gleb Smirnoff wrote:
 > On Wed, Dec 17, 2003 at 08:42:34PM +0300, Yar Tikhiy wrote:
 > Y> Would you mind testing the below version of your patch, revised.
 > Y> Please pay attention to its points:
 > Y> a) sanity check values passed through sysctl;
 > Y> b) avoid double setting nonstandard mode;
 > Y> c) format source according to style(9);
 > Y> d) initialize pppoe_mode for clarity since it's no longer
 > Y>    just a boolean trigger.
 > 
 > I have tested it on STABLE. It works OK. I have also asked PR's
 > originator to test it.
 
 Thanks!  By the way, don't you think that the default value for the
 sysctl controlling pppoe mode should be -1?  I've just read this PR
 once more and realized that the current default of 0 is *really dangerous*
 because a spurious non-standard PPPoE frame can plague an entire network!
 
 -- 
 Yar

From: Gleb Smirnoff <glebius@cell.sick.ru>
To: Yar Tikhiy <yar@FreeBSD.ORG>
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: kern/47920: if ng_pppoe switches to nonstandard mode it stays in it forever
Date: Fri, 19 Dec 2003 12:49:55 +0300

 On Thu, Dec 18, 2003 at 08:22:04PM +0300, Yar Tikhiy wrote:
 Y> Thanks!  By the way, don't you think that the default value for the
 Y> sysctl controlling pppoe mode should be -1?  I've just read this PR
 Y> once more and realized that the current default of 0 is *really dangerous*
 Y> because a spurious non-standard PPPoE frame can plague an entire network!
 
 You are absolutely right. This is a real DoS condition. I have mentioned this
 in freebsd-net, but nobody payed attention. As well as nobody payed attention
 to PR itself. May be it was ignored because of its type: "change-request", not
 "sw-bug" (originator's fault).
 
 When I submitted the patch, I wanted it to be commited as soon as possible,
 so I didn't change default behavior. AFAIK, patches that do change default
 behavior are applied more slowly. Set me right, if I mistake.
 
 So, I absolutely agree that default value should be -1. :)
 
 -- 
 Totus tuus, Glebius.
 GLEBIUS-RIPN GLEB-RIPE
State-Changed-From-To: open->patched 
State-Changed-By: yar 
State-Changed-When: Fri Dec 19 08:43:25 PST 2003 
State-Changed-Why:  
Fixed in CURRENT--the patch applied, the default mode changed to -1. 
Thanks a lot! 
MFC is due in a week. 


Responsible-Changed-From-To: freebsd-bugs->yar 
Responsible-Changed-By: yar 
Responsible-Changed-When: Fri Dec 19 08:43:25 PST 2003 
Responsible-Changed-Why:  
I'm taking care of this. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=47920 
State-Changed-From-To: patched->closed 
State-Changed-By: yar 
State-Changed-When: Mon Dec 29 06:42:17 PST 2003 
State-Changed-Why:  
This bug has been fixed in both active branches. Thanks! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=47920 
>Unformatted:
