Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 14 Feb 2018 21:17:44 +0000 (UTC)
From:      Eugene Grosbein <eugen@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r329279 - in head: share/man/man4 sys/netgraph
Message-ID:  <201802142117.w1ELHiOj031474@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: eugen
Date: Wed Feb 14 21:17:44 2018
New Revision: 329279
URL: https://svnweb.freebsd.org/changeset/base/329279

Log:
  ng_pppoe(8): add support for user-supplied Host-Uniq tag.
  
  A few ISP filter PADI requests based on such tag,
  to force the use of their own routers.
  The custom Host-Uniq tag is passed in the NGM_PPPOE_CONNECT
  control message, so it can be used with FreeBSD ppp(8)
  and mpd without any other change.
  
  Add support to send and receive PADM messages,
  HURL and MOTM, often used by service providers to provide
  ACS information and other configuration settings
  to the user CPE.
  
  Submitted by:	ale
  Approved by:	mav (mentor)
  MFC after:	1 month
  Differential Revision:	https://reviews.freebsd.org/D9270

Modified:
  head/share/man/man4/ng_pppoe.4
  head/sys/netgraph/ng_pppoe.c
  head/sys/netgraph/ng_pppoe.h

Modified: head/share/man/man4/ng_pppoe.4
==============================================================================
--- head/share/man/man4/ng_pppoe.4	Wed Feb 14 21:14:28 2018	(r329278)
+++ head/share/man/man4/ng_pppoe.4	Wed Feb 14 21:17:44 2018	(r329279)
@@ -35,7 +35,7 @@
 .\" $FreeBSD$
 .\" $Whistle: ng_pppoe.8,v 1.1 1999/01/25 23:46:27 archie Exp $
 .\"
-.Dd September 15, 2015
+.Dd February 14, 2018
 .Dt NG_PPPOE 4
 .Os
 .Sh NAME
@@ -104,12 +104,33 @@ the state machine as a client.
 It must be newly created and a service name can be given as an argument.
 It is legal to specify a zero-length service name, this is common
 on some DSL setups.
-It is possible to request a connection to a specific
-access concentrator by its name using the "AC-Name\\Service-Name" syntax.
-A session request packet will be broadcasted on the Ethernet.
+It is possible to request a connection to a specific access concentrator,
+and/or set a specific Host-Uniq tag, required by some Internet providers,
+using the
+.Qq Li [AC-Name\\][Host-Uniq|]Service-Name
+syntax.
+To set a binary Host-Uniq, it must be encoded as a hexadecimal lowercase
+string and prefixed with 
+.Qq Li 0x ,
+for example 
+.Qq Li 0x6d792d746167
+is equivalent to
+.Qq Li my-tag .
+A session request packet will be broadcast on the Ethernet.
 This command uses the
 .Dv ngpppoe_init_data
 structure shown below.
+For example, this init data argument can be used to
+connect to
+.Qq Li my-isp
+service with
+.Qq Li my-host
+uniq tag, accepting only
+.Qq Li remote-ac
+as access concentrator:
+.Bd -literal -offset indent
+"remote-ac\\my-host|my-isp"
+.Ed
 .It Dv NGM_PPPOE_LISTEN Pq Ic pppoe_listen
 Tell a nominated newly created hook that its session should enter
 the state machine as a server listener.
@@ -258,7 +279,41 @@ struct ngpppoe_maxp {
     uint16_t data;
 };
 .Ed
+.It Dv NGM_PPPOE_SEND_HURL Pq Ic send_hurl
+Tell a nominated hook with an active session to send a PADM message with
+a HURL tag.
+The argument is the URL to be delivered to the client:
+.Bd -literal -offset indent
+ngctl msg fxp0:orphans send_hurl '{ hook="myHook" data="http://example.net/cpe" }'
+.Ed
+.It Dv NGM_PPPOE_SEND_MOTM Pq Ic send_motm
+Tell a nominated hook with an active session to send a PADM message with
+a MOTM tag.
+The argument is the message to be delivered to the client:
+.Bd -literal -offset indent
+ngctl msg fxp0:orphans send_motm '{ hook="myHook" data="Welcome aboard" }'
+.Ed
 .El
+.Pp
+The two commands above use the same ngpppoe_init_data structure described
+above.
+.Bl -tag -width 3n
+.It Dv NGM_PPPOE_HURL
+This command is sent to the node that started this session when a PADM
+message with a HURL tag is received, and contains a URL that the host can
+pass to a web browser for presentation to the user.
+.It Dv NGM_PPPOE_MOTM
+This command is sent to the node that started this session when a PADM
+message with a MOTM tag is received, and contains a Message Of The
+Minute that the host can display to the user.
+.El
+.Pp
+The two commands above use a common data structure:
+.Bd -literal -offset 4n
+struct ngpppoe_padm {
+    char    msg[PPPOE_PADM_VALUE_SIZE];
+};
+.Ed
 .Sh SHUTDOWN
 This node shuts down upon receipt of a
 .Dv NGM_SHUTDOWN

Modified: head/sys/netgraph/ng_pppoe.c
==============================================================================
--- head/sys/netgraph/ng_pppoe.c	Wed Feb 14 21:14:28 2018	(r329278)
+++ head/sys/netgraph/ng_pppoe.c	Wed Feb 14 21:17:44 2018	(r329279)
@@ -175,6 +175,20 @@ static const struct ng_cmdlist ng_pppoe_cmds[] = {
 	  &ng_parse_uint16_type,
 	  NULL
 	},
+        {
+	  NGM_PPPOE_COOKIE,
+	  NGM_PPPOE_SEND_HURL,
+	  "send_hurl",
+	  &ngpppoe_init_data_state_type,
+	  NULL
+        },
+        {
+	  NGM_PPPOE_COOKIE,
+	  NGM_PPPOE_SEND_MOTM,
+	  "send_motm",
+	  &ngpppoe_init_data_state_type,
+	  NULL
+        },
 	{ 0 }
 };
 
@@ -226,9 +240,11 @@ struct sess_neg {
 	const struct pppoe_tag	*tags[NUMTAGS];
 	u_int			service_len;
 	u_int			ac_name_len;
+	u_int			host_uniq_len;
 
 	struct datatag		service;
 	struct datatag		ac_name;
+	struct datatag		host_uniq;
 };
 typedef struct sess_neg *negp;
 
@@ -589,22 +605,47 @@ static hook_p
 pppoe_finduniq(node_p node, const struct pppoe_tag *tag)
 {
 	hook_p	hook = NULL;
-	union uniq uniq;
+	sessp	sp;
 
-	bcopy(tag + 1, uniq.bytes, sizeof(void *));
 	/* Cycle through all known hooks. */
 	LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) {
 		/* Skip any nonsession hook. */
 		if (NG_HOOK_PRIVATE(hook) == NULL)
 			continue;
-		if (uniq.pointer == NG_HOOK_PRIVATE(hook))
+		sp = NG_HOOK_PRIVATE(hook);
+		/* Skip already connected sessions. */
+		if (sp->neg == NULL)
+			continue;
+		if (sp->neg->host_uniq_len == ntohs(tag->tag_len) &&
+		    bcmp(sp->neg->host_uniq.data, (const char *)(tag + 1),
+		     sp->neg->host_uniq_len) == 0)
 			break;
 	}
-	CTR3(KTR_NET, "%20s: matched %p for %p", __func__, hook, uniq.pointer);
+	CTR3(KTR_NET, "%20s: matched %p for %p", __func__, hook, sp);
 
 	return (hook);
 }
 
+static hook_p
+pppoe_findcookie(node_p node, const struct pppoe_tag *tag)
+{
+	hook_p	hook = NULL;
+	union uniq cookie;
+
+	bcopy(tag + 1, cookie.bytes, sizeof(void *));
+	/* Cycle through all known hooks. */
+	LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) {
+		/* Skip any nonsession hook. */
+		if (NG_HOOK_PRIVATE(hook) == NULL)
+			continue;
+		if (cookie.pointer == NG_HOOK_PRIVATE(hook))
+			break;
+	}
+	CTR3(KTR_NET, "%20s: matched %p for %p", __func__, hook, cookie.pointer);
+
+	return (hook);
+}
+
 /**************************************************************************
  * Start of Netgraph entrypoints.					  *
  **************************************************************************/
@@ -744,17 +785,29 @@ ng_pppoe_rcvmsg(node_p node, item_p item, hook_p lasth
 		case NGM_PPPOE_LISTEN:
 		case NGM_PPPOE_OFFER:
 		case NGM_PPPOE_SERVICE:
+		case NGM_PPPOE_SEND_HURL:
+		case NGM_PPPOE_SEND_MOTM:
 			ourmsg = (struct ngpppoe_init_data *)msg->data;
 			if (msg->header.arglen < sizeof(*ourmsg)) {
 				log(LOG_ERR, "ng_pppoe[%x]: init data too "
 				    "small\n", node->nd_ID);
 				LEAVE(EMSGSIZE);
 			}
-			if (msg->header.arglen - sizeof(*ourmsg) >
-			    PPPOE_SERVICE_NAME_SIZE) {
-				log(LOG_ERR, "ng_pppoe[%x]: service name "
-				    "too big\n", node->nd_ID);
-				LEAVE(EMSGSIZE);
+			if (msg->header.cmd == NGM_PPPOE_SEND_HURL ||
+			    msg->header.cmd == NGM_PPPOE_SEND_MOTM) {
+				if (msg->header.arglen - sizeof(*ourmsg) >
+				    PPPOE_PADM_VALUE_SIZE) {
+					log(LOG_ERR, "ng_pppoe[%x]: message "
+					    "too big\n", node->nd_ID);
+					LEAVE(EMSGSIZE);
+				}
+			} else {
+				if (msg->header.arglen - sizeof(*ourmsg) >
+				    PPPOE_SERVICE_NAME_SIZE) {
+					log(LOG_ERR, "ng_pppoe[%x]: service name "
+					    "too big\n", node->nd_ID);
+					LEAVE(EMSGSIZE);
+				}
 			}
 			if (msg->header.arglen - sizeof(*ourmsg) <
 			    ourmsg->data_len) {
@@ -794,6 +847,20 @@ ng_pppoe_rcvmsg(node_p node, item_p item, hook_p lasth
 			if (msg->header.cmd == NGM_PPPOE_SERVICE)
 				break;
 
+			/*
+			 * PADM messages are set up on active sessions.
+			 */
+			if (msg->header.cmd == NGM_PPPOE_SEND_HURL ||
+			    msg->header.cmd == NGM_PPPOE_SEND_MOTM) {
+				if (sp->state != PPPOE_NEWCONNECTED &&
+				    sp->state != PPPOE_CONNECTED) {
+					log(LOG_NOTICE, "ng_pppoe[%x]: session is not "
+					    "active\n", node->nd_ID);
+					LEAVE(EISCONN);
+				}
+				break;
+			}
+
 			if (sp->state != PPPOE_SNONE) {
 				log(LOG_NOTICE, "ng_pppoe[%x]: Session already "
 				    "active\n", node->nd_ID);
@@ -848,12 +915,15 @@ ng_pppoe_rcvmsg(node_p node, item_p item, hook_p lasth
 			 * Check the hook exists and is Uninitialised.
 			 * Send a PADI request, and start the timeout logic.
 			 * Store the originator of this message so we can send
-			 * a success of fail message to them later.
+			 * a success or fail message to them later.
 			 * Move the session to SINIT.
 			 * Set up the session to the correct state and
 			 * start it.
 			 */
-			int	i, acnlen = 0, acnsep = 0, srvlen;
+			int	acnpos, acnlen = 0, acnsep = 0;
+			int	hupos, hulen = 0, husep = 0;
+			int	i, srvpos, srvlen;
+			acnpos = 0;
 			for (i = 0; i < ourmsg->data_len; i++) {
 				if (ourmsg->data[i] == '\\') {
 					acnlen = i;
@@ -861,15 +931,56 @@ ng_pppoe_rcvmsg(node_p node, item_p item, hook_p lasth
 					break;
 				}
 			}
-			srvlen = ourmsg->data_len - acnlen - acnsep;
+			hupos = acnlen + acnsep;
+			for (i = hupos; i < ourmsg->data_len; i++) {
+				if (ourmsg->data[i] == '|') {
+					hulen = i - hupos;
+					husep = 1;
+					break;
+				}
+			}
+			srvpos = hupos + hulen + husep;
+			srvlen = ourmsg->data_len - srvpos;
 
-			bcopy(ourmsg->data, neg->ac_name.data, acnlen);
+			bcopy(ourmsg->data + acnpos, neg->ac_name.data, acnlen);
 			neg->ac_name_len = acnlen;
 
+			neg->host_uniq.hdr.tag_type = PTT_HOST_UNIQ;
+			if (hulen == 0) {
+				/* Not provided, generate one */
+				neg->host_uniq.hdr.tag_len = htons(sizeof(sp));
+				bcopy(&sp, neg->host_uniq.data, sizeof(sp));
+				neg->host_uniq_len = sizeof(sp);
+			} else if (hulen > 2 && ourmsg->data[hupos] == '0' &&
+			  ourmsg->data[hupos + 1] == 'x' && hulen % 2 == 0) {
+				/* Hex encoded */
+				static const char hexdig[16] = "0123456789abcdef";
+				int j;
+
+				neg->host_uniq.hdr.tag_len = htons((uint16_t)(hulen / 2 - 1));
+				for (i = 0; i < hulen - 2; i++) {
+					for (j = 0;
+					     j < 16 &&
+					     ourmsg->data[hupos + 2 + i] != hexdig[j];
+					     j++);
+					if (j == 16)
+						LEAVE(EINVAL);
+					if (i % 2 == 0)
+						neg->host_uniq.data[i / 2] = j << 4;
+					else
+						neg->host_uniq.data[i / 2] |= j;
+				}
+				neg->host_uniq_len = hulen / 2 - 1;
+			} else {
+				/* Plain string */
+				neg->host_uniq.hdr.tag_len = htons((uint16_t)hulen);
+				bcopy(ourmsg->data + hupos, neg->host_uniq.data, hulen);
+				neg->host_uniq_len = hulen;
+			}
+
 			neg->service.hdr.tag_type = PTT_SRV_NAME;
 			neg->service.hdr.tag_len = htons((uint16_t)srvlen);
-			bcopy(ourmsg->data + acnlen + acnsep,
-			    neg->service.data, srvlen);
+			bcopy(ourmsg->data + srvpos, neg->service.data, srvlen);
 			neg->service_len = srvlen;
 			pppoe_start(sp);
 			break;
@@ -879,7 +990,7 @@ ng_pppoe_rcvmsg(node_p node, item_p item, hook_p lasth
 			 * Check the hook exists and is Uninitialised.
 			 * Install the service matching string.
 			 * Store the originator of this message so we can send
-			 * a success of fail message to them later.
+			 * a success or fail message to them later.
 			 * Move the hook to 'LISTENING'
 			 */
 			neg->service.hdr.tag_type = PTT_SRV_NAME;
@@ -1019,6 +1130,92 @@ ng_pppoe_rcvmsg(node_p node, item_p item, hook_p lasth
 			privp->max_payload.hdr.tag_len = htons(sizeof(uint16_t));
 			privp->max_payload.data = htons(*((uint16_t *)msg->data));
 			break;
+		case NGM_PPPOE_SEND_HURL:
+		    {
+			struct mbuf *m;
+
+			/* Generate a packet of that type. */
+			m = m_gethdr(M_NOWAIT, MT_DATA);
+			if (m == NULL)
+				log(LOG_NOTICE, "ng_pppoe[%x]: session out of "
+				    "mbufs\n", node->nd_ID);
+			else {
+				struct pppoe_full_hdr *wh;
+				struct pppoe_tag *tag;
+				int     error = 0;
+
+				wh = mtod(m, struct pppoe_full_hdr *);
+				bcopy(&sp->pkt_hdr, wh, sizeof(*wh));
+
+				/* Revert the stored header to DISC/PADM mode. */
+				wh->ph.code = PADM_CODE;
+				/*
+				 * Configure ethertype depending on what
+				 * was used during sessions stage.
+				 */
+				if (wh->eh.ether_type ==
+				    ETHERTYPE_PPPOE_3COM_SESS)
+					wh->eh.ether_type = ETHERTYPE_PPPOE_3COM_DISC;
+				else
+					wh->eh.ether_type = ETHERTYPE_PPPOE_DISC;
+				/*
+				 * Add PADM message and adjust sizes.
+				 */
+				tag = (void *)(&wh->ph + 1);
+				tag->tag_type = PTT_HURL;
+				tag->tag_len = htons(ourmsg->data_len);
+				strncpy((char *)(tag + 1), ourmsg->data, ourmsg->data_len);
+				m->m_pkthdr.len = m->m_len = sizeof(*wh) + sizeof(*tag) +
+				    ourmsg->data_len;
+				wh->ph.length = htons(sizeof(*tag) + ourmsg->data_len);
+				NG_SEND_DATA_ONLY(error,
+				    privp->ethernet_hook, m);
+			}
+			break;
+		    }
+		case NGM_PPPOE_SEND_MOTM:
+		    {
+			struct mbuf *m;
+
+			/* Generate a packet of that type. */
+			m = m_gethdr(M_NOWAIT, MT_DATA);
+			if (m == NULL)
+				log(LOG_NOTICE, "ng_pppoe[%x]: session out of "
+				    "mbufs\n", node->nd_ID);
+			else {
+				struct pppoe_full_hdr *wh;
+				struct pppoe_tag *tag;
+				int     error = 0;
+
+				wh = mtod(m, struct pppoe_full_hdr *);
+				bcopy(&sp->pkt_hdr, wh, sizeof(*wh));
+
+				/* Revert the stored header to DISC/PADM mode. */
+				wh->ph.code = PADM_CODE;
+				/*
+				 * Configure ethertype depending on what
+				 * was used during sessions stage.
+				 */
+				if (wh->eh.ether_type ==
+				    ETHERTYPE_PPPOE_3COM_SESS)
+					wh->eh.ether_type = ETHERTYPE_PPPOE_3COM_DISC;
+				else
+					wh->eh.ether_type = ETHERTYPE_PPPOE_DISC;
+				/*
+				 * Add PADM message and adjust sizes.
+				 */
+				tag = (void *)(&wh->ph + 1);
+				tag->tag_type = PTT_MOTM;
+				tag->tag_len = htons(ourmsg->data_len);
+				strncpy((char *)(tag + 1), ourmsg->data, ourmsg->data_len);
+				m->m_pkthdr.len = m->m_len = sizeof(*wh) + sizeof(*tag) +
+				    ourmsg->data_len;
+				wh->ph.length = htons(sizeof(*tag) + ourmsg->data_len);
+				NG_SEND_DATA_ONLY(error,
+				    privp->ethernet_hook, m);
+			}
+			break;
+		    }
 		default:
 			LEAVE(EINVAL);
 		}
@@ -1061,10 +1258,6 @@ pppoe_start(sessp sp)
 	node_p	node = NG_HOOK_NODE(hook);
 	priv_p	privp = NG_NODE_PRIVATE(node);
 	negp	neg = sp->neg;
-	struct {
-		struct pppoe_tag hdr;
-		union	uniq	data;
-	} __packed uniqtag;
 	struct  mbuf *m0;
 	int	error;
 
@@ -1080,11 +1273,8 @@ pppoe_start(sessp sp)
 	memcpy((void *)&neg->pkt->pkt_header.eh, &privp->eh,
 	    sizeof(struct ether_header));
 	neg->pkt->pkt_header.ph.code = PADI_CODE;
-	uniqtag.hdr.tag_type = PTT_HOST_UNIQ;
-	uniqtag.hdr.tag_len = htons((u_int16_t)sizeof(uniqtag.data));
-	uniqtag.data.pointer = sp;
 	init_tags(sp);
-	insert_tag(sp, &uniqtag.hdr);
+	insert_tag(sp, &neg->host_uniq.hdr);
 	insert_tag(sp, &neg->service.hdr);
 	if (privp->max_payload.data != 0)
 		insert_tag(sp, &privp->max_payload.hdr);
@@ -1163,6 +1353,52 @@ send_maxp(sessp sp, const struct pppoe_tag *tag)
 	return (error);
 }
 
+static int
+send_hurl(sessp sp, const struct pppoe_tag *tag)
+{
+	int error, tlen;
+	struct ng_mesg *msg;
+	struct ngpppoe_padm *padm;
+
+	CTR2(KTR_NET, "%20s: called %d", __func__, sp->Session_ID);
+
+	NG_MKMESSAGE(msg, NGM_PPPOE_COOKIE, NGM_PPPOE_HURL,
+	    sizeof(struct ngpppoe_padm), M_NOWAIT);
+	if (msg == NULL)
+		return (ENOMEM);
+
+	padm = (struct ngpppoe_padm *)msg->data;
+	tlen = min(PPPOE_PADM_VALUE_SIZE - 1, ntohs(tag->tag_len));
+	strncpy(padm->msg, (const char *)(tag + 1), tlen);
+	padm->msg[tlen] = '\0';
+	NG_SEND_MSG_ID(error, NG_HOOK_NODE(sp->hook), msg, sp->creator, 0);
+
+	return (error);
+}
+
+static int
+send_motm(sessp sp, const struct pppoe_tag *tag)
+{
+	int error, tlen;
+	struct ng_mesg *msg;
+	struct ngpppoe_padm *padm;
+
+	CTR2(KTR_NET, "%20s: called %d", __func__, sp->Session_ID);
+
+	NG_MKMESSAGE(msg, NGM_PPPOE_COOKIE, NGM_PPPOE_MOTM,
+	    sizeof(struct ngpppoe_padm), M_NOWAIT);
+	if (msg == NULL)
+		return (ENOMEM);
+
+	padm = (struct ngpppoe_padm *)msg->data;
+	tlen = min(PPPOE_PADM_VALUE_SIZE - 1, ntohs(tag->tag_len));
+	strncpy(padm->msg, (const char *)(tag + 1), tlen);
+	padm->msg[tlen] = '\0';
+	NG_SEND_MSG_ID(error, NG_HOOK_NODE(sp->hook), msg, sp->creator, 0);
+
+	return (error);
+}
+
 /*
  * Receive data from session hook and do something with it.
  */
@@ -1320,6 +1556,7 @@ ng_pppoe_rcvdata_ether(hook_p hook, item_p item)
 	const priv_p		privp = NG_NODE_PRIVATE(node);
 	sessp			sp;
 	const struct pppoe_tag	*utag = NULL, *tag = NULL;
+	const struct pppoe_tag	sntag = { PTT_SRV_NAME, 0 };
 	const struct pppoe_full_hdr *wh;
 	const struct pppoe_hdr	*ph;
 	negp			neg = NULL;
@@ -1409,11 +1646,8 @@ ng_pppoe_rcvdata_ether(hook_p hook, item_p item)
 			 * processing.
 			 */
 			tag = get_tag(ph, PTT_SRV_NAME);
-			if (tag == NULL) {
-				CTR1(KTR_NET, "%20s: PADI w/o Service-Name",
-				    __func__);
-				LEAVE(ENETUNREACH);
-			}
+			if (tag == NULL)
+				tag = &sntag;
 
 			/*
 			 * First, try to match Service-Name against our 
@@ -1438,8 +1672,7 @@ ng_pppoe_rcvdata_ether(hook_p hook, item_p item)
 			 * For now simply accept the first we receive.
 			 */
 			utag = get_tag(ph, PTT_HOST_UNIQ);
-			if ((utag == NULL) ||
-			    (ntohs(utag->tag_len) != sizeof(sp))) {
+			if (utag == NULL) {
 				log(LOG_NOTICE, "ng_pppoe[%x]: no host "
 				    "unique field\n", node->nd_ID);
 				LEAVE(ENETUNREACH);
@@ -1529,7 +1762,7 @@ ng_pppoe_rcvdata_ether(hook_p hook, item_p item)
 				LEAVE(ENETUNREACH);
 			}
 
-			sendhook = pppoe_finduniq(node, utag);
+			sendhook = pppoe_findcookie(node, utag);
 			if (sendhook == NULL)
 				LEAVE(ENETUNREACH);
 
@@ -1605,8 +1838,7 @@ ng_pppoe_rcvdata_ether(hook_p hook, item_p item)
 			 * set us into Session mode.
 			 */
 			utag = get_tag(ph, PTT_HOST_UNIQ);
-			if ((utag == NULL) ||
-			    (ntohs(utag->tag_len) != sizeof(sp))) {
+			if (utag == NULL) {
 				LEAVE (ENETUNREACH);
 			}
 			sendhook = pppoe_finduniq(node, utag);
@@ -1659,6 +1891,19 @@ ng_pppoe_rcvdata_ether(hook_p hook, item_p item)
 			/* Disconnect that hook. */
 			ng_rmhook_self(sp->hook);
 			break;
+		case	PADM_CODE:
+			/*
+			 * We are a client:
+			 * find matching peer/session combination.
+			 */
+			sp = pppoe_findsession(privp, wh);
+			if (sp == NULL)
+				LEAVE (ENETUNREACH);
+			if ((tag = get_tag(ph, PTT_HURL)))
+				send_hurl(sp, tag);
+			if ((tag = get_tag(ph, PTT_MOTM)))
+				send_motm(sp, tag);
+			break;
 		default:
 			LEAVE(EPFNOSUPPORT);
 		}
@@ -1781,7 +2026,7 @@ ng_pppoe_disconnect(hook_p hook)
 			struct mbuf *m;
 
 			/* Generate a packet of that type. */
-			MGETHDR(m, M_NOWAIT, MT_DATA);
+			m = m_gethdr(M_NOWAIT, MT_DATA);
 			if (m == NULL)
 				log(LOG_NOTICE, "ng_pppoe[%x]: session out of "
 				    "mbufs\n", node->nd_ID);
@@ -1791,8 +2036,6 @@ ng_pppoe_disconnect(hook_p hook)
 				int	msglen = strlen(SIGNOFF);
 				int	error = 0;
 
-				m->m_pkthdr.rcvif = NULL;
-				m->m_pkthdr.len = m->m_len = sizeof(*wh);
 				wh = mtod(m, struct pppoe_full_hdr *);
 				bcopy(&sp->pkt_hdr, wh, sizeof(*wh));
 
@@ -1815,8 +2058,8 @@ ng_pppoe_disconnect(hook_p hook)
 				tag->tag_type = PTT_GEN_ERR;
 				tag->tag_len = htons((u_int16_t)msglen);
 				strncpy((char *)(tag + 1), SIGNOFF, msglen);
-				m->m_pkthdr.len = (m->m_len += sizeof(*tag) +
-				    msglen);
+				m->m_pkthdr.len = m->m_len = sizeof(*wh) + sizeof(*tag) +
+				    msglen;
 				wh->ph.length = htons(sizeof(*tag) + msglen);
 				NG_SEND_DATA_ONLY(error,
 					privp->ethernet_hook, m);
@@ -1933,6 +2176,8 @@ scan_tags(sessp	sp, const struct pppoe_hdr* ph)
 		case	PTT_SYS_ERR:
 		case	PTT_GEN_ERR:
 		case	PTT_MAX_PAYL:
+		case	PTT_HURL:
+		case	PTT_MOTM:
 			break;
 		}
 		pt = (const struct pppoe_tag*)ptn;

Modified: head/sys/netgraph/ng_pppoe.h
==============================================================================
--- head/sys/netgraph/ng_pppoe.h	Wed Feb 14 21:14:28 2018	(r329278)
+++ head/sys/netgraph/ng_pppoe.h	Wed Feb 14 21:17:44 2018	(r329279)
@@ -52,8 +52,10 @@
 
 #define NGM_PPPOE_COOKIE		1089893072
 #define NGM_PPPOE_SETMAXP_COOKIE	1441624322
+#define NGM_PPPOE_PADM_COOKIE		1488405822
 
 #define	PPPOE_SERVICE_NAME_SIZE		64 /* for now */
+#define	PPPOE_PADM_VALUE_SIZE		128 /* for now */
 
 /* Hook names */
 #define NG_PPPOE_HOOK_ETHERNET	"ethernet"
@@ -84,7 +86,11 @@ enum cmd {
 	NGM_PPPOE_SETMODE  = 12, /* set to standard or compat modes */
 	NGM_PPPOE_GETMODE  = 13, /* see current mode */
 	NGM_PPPOE_SETENADDR = 14, /* set Ethernet address */
-	NGM_PPPOE_SETMAXP  = 15 /* Set PPP-Max-Payload value */
+	NGM_PPPOE_SETMAXP   = 15, /* Set PPP-Max-Payload value */
+	NGM_PPPOE_SEND_HURL = 16, /* Send PADM HURL message */
+	NGM_PPPOE_HURL      = 17, /* HURL for informational purposes */
+	NGM_PPPOE_SEND_MOTM = 18, /* Send PADM MOTM message */
+	NGM_PPPOE_MOTM      = 19  /* MOTM for informational purposes */
 };
 
 /***********************
@@ -157,6 +163,13 @@ struct ngpppoe_maxp {
 	uint16_t	data;
 };
 
+/*
+ * This structure is used to send PADM messages from server to client.
+ */
+struct ngpppoe_padm {
+	char	msg[PPPOE_PADM_VALUE_SIZE];
+};
+
 /********************************************************************
  * Constants and definitions specific to pppoe
  ********************************************************************/
@@ -171,6 +184,7 @@ struct ngpppoe_maxp {
 #define PADR_CODE	0x19
 #define PADS_CODE	0x65
 #define PADT_CODE	0xa7
+#define PADM_CODE	0xd3
 
 /* Tag identifiers */
 #if BYTE_ORDER == BIG_ENDIAN
@@ -181,6 +195,8 @@ struct ngpppoe_maxp {
 #define PTT_AC_COOKIE	(0x0104)
 #define PTT_VENDOR 	(0x0105)
 #define PTT_RELAY_SID	(0x0110)
+#define PTT_HURL	(0x0111)	/* PPPoE Extensions (CARREL) */
+#define PTT_MOTM	(0x0112)	/* PPPoE Extensions (CARREL) */
 #define	PTT_MAX_PAYL	(0x0120)	/* PPP-Max-Payload (RFC4638) */
 #define PTT_SRV_ERR     (0x0201)
 #define PTT_SYS_ERR  	(0x0202)
@@ -198,6 +214,8 @@ struct ngpppoe_maxp {
 #define PTT_AC_COOKIE	(0x0401)
 #define PTT_VENDOR 	(0x0501)
 #define PTT_RELAY_SID	(0x1001)
+#define PTT_HURL	(0x1101)	/* PPPoE Extensions (CARREL) */
+#define PTT_MOTM	(0x1201)	/* PPPoE Extensions (CARREL) */
 #define	PTT_MAX_PAYL	(0x2001)	/* PPP-Max-Payload (RFC4638) */
 #define PTT_SRV_ERR     (0x0102)
 #define PTT_SYS_ERR  	(0x0202)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201802142117.w1ELHiOj031474>