ale updated this revision to Diff 27059.
ale added a comment.

  Addressed latest comments, updated also the pppoe disconnect function.
  Please check the correctness, and commit the patch if you are satisfied.

REPOSITORY
  rS FreeBSD src repository

CHANGES SINCE LAST UPDATE
  https://reviews.freebsd.org/D9270?vs=25977&id=27059

REVISION DETAIL
  https://reviews.freebsd.org/D9270

AFFECTED FILES
  share/man/man4/ng_pppoe.4
  sys/netgraph/ng_pppoe.c
  sys/netgraph/ng_pppoe.h

EMAIL PREFERENCES
  https://reviews.freebsd.org/settings/panel/emailpreferences/

To: ale, #manpages, wblock, #network, julian, mav, adrian, glebius
Cc: glebius, wblock, mav, poolroom_gmail.com, mandree, imp, freebsd-net-list
diff --git a/sys/netgraph/ng_pppoe.h b/sys/netgraph/ng_pppoe.h
--- a/sys/netgraph/ng_pppoe.h
+++ b/sys/netgraph/ng_pppoe.h
@@ -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 @@
 	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 @@
 	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 @@
 #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 @@
 #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 @@
 #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)
diff --git a/sys/netgraph/ng_pppoe.c b/sys/netgraph/ng_pppoe.c
--- a/sys/netgraph/ng_pppoe.c
+++ b/sys/netgraph/ng_pppoe.c
@@ -175,6 +175,20 @@
 	  &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 @@
 	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,18 +605,40 @@
 pppoe_finduniq(node_p node, const struct pppoe_tag *tag)
 {
 	hook_p	hook = NULL;
-	union uniq uniq;
+	sessp	sp;
+
+	/* Cycle through all known hooks. */
+	LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) {
+		/* Skip any nonsession hook. */
+		if (NG_HOOK_PRIVATE(hook) == NULL)
+			continue;
+		sp = NG_HOOK_PRIVATE(hook);
+		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, 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, uniq.bytes, sizeof(void *));
+	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 (uniq.pointer == NG_HOOK_PRIVATE(hook))
+		if (cookie.pointer == NG_HOOK_PRIVATE(hook))
 			break;
 	}
-	CTR3(KTR_NET, "%20s: matched %p for %p", __func__, hook, uniq.pointer);
+	CTR3(KTR_NET, "%20s: matched %p for %p", __func__, hook, cookie.pointer);
 
 	return (hook);
 }
@@ -744,17 +782,29 @@
 		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 +844,20 @@
 			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,28 +912,72 @@
 			 * 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;
 					acnsep = 1;
 					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 +987,7 @@
 			 * 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 +1127,92 @@
 			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 +1255,6 @@
 	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 +1270,8 @@
 	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 +1350,52 @@
 	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 +1553,7 @@
 	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 +1643,8 @@
 			 * 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 +1669,7 @@
 			 * 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 +1759,7 @@
 				LEAVE(ENETUNREACH);
 			}
 
-			sendhook = pppoe_finduniq(node, utag);
+			sendhook = pppoe_findcookie(node, utag);
 			if (sendhook == NULL)
 				LEAVE(ENETUNREACH);
 
@@ -1605,8 +1835,7 @@
 			 * 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 +1888,19 @@
 			/* 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 +2023,7 @@
 			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 +2033,6 @@
 				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 +2055,8 @@
 				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 +2173,8 @@
 		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;
diff --git a/share/man/man4/ng_pppoe.4 b/share/man/man4/ng_pppoe.4
--- a/share/man/man4/ng_pppoe.4
+++ b/share/man/man4/ng_pppoe.4
@@ -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 April 4, 2017
 .Dt NG_PPPOE 4
 .Os
 .Sh NAME
@@ -104,12 +104,33 @@
 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 @@
     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

_______________________________________________
freebsd-net@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/freebsd-net
To unsubscribe, send any mail to "freebsd-net-unsubscr...@freebsd.org"

Reply via email to