From owner-svn-src-head@freebsd.org Wed Feb 14 21:17:45 2018 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 0D5FEF21128; Wed, 14 Feb 2018 21:17:45 +0000 (UTC) (envelope-from eugen@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id AC4D06DCE8; Wed, 14 Feb 2018 21:17:44 +0000 (UTC) (envelope-from eugen@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id A2FD61531A; Wed, 14 Feb 2018 21:17:44 +0000 (UTC) (envelope-from eugen@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w1ELHiUN031477; Wed, 14 Feb 2018 21:17:44 GMT (envelope-from eugen@FreeBSD.org) Received: (from eugen@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w1ELHiOj031474; Wed, 14 Feb 2018 21:17:44 GMT (envelope-from eugen@FreeBSD.org) Message-Id: <201802142117.w1ELHiOj031474@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: eugen set sender to eugen@FreeBSD.org using -f From: Eugene Grosbein Date: Wed, 14 Feb 2018 21:17:44 +0000 (UTC) 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 X-SVN-Group: head X-SVN-Commit-Author: eugen X-SVN-Commit-Paths: in head: share/man/man4 sys/netgraph X-SVN-Commit-Revision: 329279 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.25 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 14 Feb 2018 21:17:45 -0000 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)