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)
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to