Author: eugen
Date: Fri Mar 16 15:10:13 2018
New Revision: 331059
URL: https://svnweb.freebsd.org/changeset/base/331059

Log:
  MFC r329279: add support for user-supplied Host-Uniq tag to ng_pppoe(4).
  
  Submitted by:         ale
  Approved by:          mav (mentor)
  Relnotes:             yes
  Differential Revision:        https://reviews.freebsd.org/D9270

Modified:
  stable/10/share/man/man4/ng_pppoe.4
  stable/10/sys/netgraph/ng_pppoe.c
  stable/10/sys/netgraph/ng_pppoe.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/share/man/man4/ng_pppoe.4
==============================================================================
--- stable/10/share/man/man4/ng_pppoe.4 Fri Mar 16 15:04:13 2018        
(r331058)
+++ stable/10/share/man/man4/ng_pppoe.4 Fri Mar 16 15:10:13 2018        
(r331059)
@@ -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: stable/10/sys/netgraph/ng_pppoe.c
==============================================================================
--- stable/10/sys/netgraph/ng_pppoe.c   Fri Mar 16 15:04:13 2018        
(r331058)
+++ stable/10/sys/netgraph/ng_pppoe.c   Fri Mar 16 15:10:13 2018        
(r331059)
@@ -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: stable/10/sys/netgraph/ng_pppoe.h
==============================================================================
--- stable/10/sys/netgraph/ng_pppoe.h   Fri Mar 16 15:04:13 2018        
(r331058)
+++ stable/10/sys/netgraph/ng_pppoe.h   Fri Mar 16 15:10:13 2018        
(r331059)
@@ -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)
_______________________________________________
svn-src-stable-10@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10
To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"

Reply via email to