46#include <sys/kernel.h>
49#include <sys/malloc.h>
52#include <sys/syslog.h>
53#include <net/ethernet.h>
61#ifdef NG_SEPARATE_MALLOC
64#define M_NETGRAPH_PPPOE M_NETGRAPH
67#define SIGNOFF "session closed"
266#define SESSHASHSIZE 0x0100
267#define SESSHASH(x) (((x) ^ ((x) >> 8)) & (SESSHASHSIZE - 1))
284#define COMPAT_3COM 0x00000001
285#define COMPAT_DLINK 0x00000002
286 struct ether_header
eh;
298#define LEAVE(x) do { error = x; goto quit; } while(0)
316 return (
const struct pppoe_tag*)(((
const char*)(ph + 1))
328 const char *
const end = (
const char *)
next_tag(ph);
329 const struct pppoe_tag *pt = (
const void *)(ph + 1);
335 while((
const char*)(pt + 1) <= end) {
339 ptn = (((
const char *)(pt + 1)) + ntohs(pt->
tag_len));
341 CTR2(KTR_NET,
"%20s: invalid length for tag %d",
346 CTR2(KTR_NET,
"%20s: found tag %d", __func__, idx);
353 CTR2(KTR_NET,
"%20s: not found tag %d", __func__, idx);
366 KASSERT(sp->
neg != NULL, (
"%s: no neg", __func__));
376 KASSERT(neg != NULL, (
"%s: no neg", __func__));
380 log(LOG_NOTICE,
"ng_pppoe: asked to add too many tags to "
403 KASSERT((sp->
neg != NULL) && (sp->
neg->
m != NULL),
404 (
"%s: called from wrong state", __func__));
405 CTR2(KTR_NET,
"%20s: called %d", __func__, sp->
Session_ID);
407 dp = (
char *)(&wh->
ph + 1);
411 tlen = ntohs((*tag)->tag_len) +
sizeof(**tag);
412 if ((
length + tlen) > (ETHER_MAX_LEN - 4 -
sizeof(*wh))) {
413 log(LOG_NOTICE,
"ng_pppoe: tags too long\n");
417 bcopy(*tag, (
char *)dp, tlen);
423 sp->
neg->
m->m_pkthdr.len =
length +
sizeof(*wh);
445 LIST_FOREACH(sp, &privp->listeners, sessions) {
460 if (strncmp((
const char *)(tag + 1), neg->
service.
data,
464 CTR3(KTR_NET,
"%20s: matched %p for %s", __func__,
465 sp?sp->
hook:NULL, (
const char *)(tag + 1));
467 return (sp?sp->
hook:NULL);
483 LIST_FOREACH(sp, &privp->listeners, sessions) {
486 m = m_dup(m0, M_NOWAIT);
506 LIST_FOREACH(sp, &privp->listeners, sessions) {
510 strncmp(svc_name, neg->
service.
data, svc_len) == 0)
525 static uint16_t pppoe_sid = 1;
533 if (val == 0xffff || val == 0x0000)
538 mtx_lock(&privp->sesshash[hash].mtx);
539 LIST_FOREACH(tsp, &privp->sesshash[hash].head, sessions) {
545 LIST_INSERT_HEAD(&privp->sesshash[hash].head, sp, sessions);
547 mtx_unlock(&privp->sesshash[hash].mtx);
551 CTR2(KTR_NET,
"%20s: new sid %d", __func__, val);
563 mtx_lock(&privp->sesshash[hash].mtx);
564 LIST_INSERT_HEAD(&privp->sesshash[hash].head, sp, sessions);
565 mtx_unlock(&privp->sesshash[hash].mtx);
575 mtx_lock(&privp->sesshash[hash].mtx);
576 LIST_REMOVE(sp, sessions);
577 mtx_unlock(&privp->sesshash[hash].mtx);
584 uint16_t session = ntohs(wh->
ph.
sid);
588 mtx_lock(&privp->sesshash[hash].mtx);
589 LIST_FOREACH(sp, &privp->sesshash[hash].head, sessions) {
592 wh->
eh.ether_shost, ETHER_ADDR_LEN) == 0) {
596 mtx_unlock(&privp->sesshash[hash].mtx);
597 CTR3(KTR_NET,
"%20s: matched %p for %d", __func__, sp?sp->
hook:NULL,
610 LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) {
623 CTR3(KTR_NET,
"%20s: matched %p for %p", __func__, hook, sp);
634 bcopy(tag + 1, cookie.
bytes,
sizeof(
void *));
636 LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) {
643 CTR3(KTR_NET,
"%20s: matched %p for %p", __func__, hook, cookie.
pointer);
669 memset(&privp->eh.ether_dhost, 0xff, ETHER_ADDR_LEN);
672 LIST_INIT(&privp->listeners);
674 mtx_init(&privp->sesshash[i].mtx,
"PPPoE hash mutex", NULL, MTX_DEF);
675 LIST_INIT(&privp->sesshash[i].head);
678 CTR3(KTR_NET,
"%20s: created node [%x] (%p)",
679 __func__, node->
nd_ID, node);
700 privp->ethernet_hook = hook;
703 privp->debug_hook = hook;
718 CTR5(KTR_NET,
"%20s: node [%x] (%p) connected hook %s (%p)",
719 __func__, node->
nd_ID, node,
name, hook);
735 if (hook != privp->ethernet_hook)
765 struct epoch_tracker et;
776 CTR5(KTR_NET,
"%20s: node [%x] (%p) got message %d with cookie %d",
792 log(LOG_ERR,
"ng_pppoe[%x]: init data too "
793 "small\n", node->
nd_ID);
800 log(LOG_ERR,
"ng_pppoe[%x]: message "
801 "too big\n", node->
nd_ID);
807 log(LOG_ERR,
"ng_pppoe[%x]: service name "
808 "too big\n", node->
nd_ID);
814 log(LOG_ERR,
"ng_pppoe[%x]: init data has bad "
815 "length, %d should be %zd\n", node->
nd_ID,
822 ourmsg->
hook[
sizeof(ourmsg->
hook) - 1] =
'\0';
857 log(LOG_NOTICE,
"ng_pppoe[%x]: session is not "
858 "active\n", node->
nd_ID);
865 log(LOG_NOTICE,
"ng_pppoe[%x]: Session already "
866 "active\n", node->
nd_ID);
879 neg->
m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
880 if (neg->
m == NULL) {
884 neg->
m->m_pkthdr.rcvif = NULL;
890 &privp->eh,
sizeof(
struct ether_header));
908 stats->packets_in = privp->packets_in;
909 stats->packets_out = privp->packets_out;
923 int acnpos, acnlen = 0, acnsep = 0;
924 int hupos, hulen = 0, husep = 0;
925 int i, srvpos, srvlen;
927 for (i = 0; i < ourmsg->
data_len; i++) {
928 if (ourmsg->
data[i] ==
'\\') {
934 hupos = acnlen + acnsep;
935 for (i = hupos; i < ourmsg->
data_len; i++) {
936 if (ourmsg->
data[i] ==
'|') {
942 srvpos = hupos + hulen + husep;
954 }
else if (hulen > 2 && ourmsg->
data[hupos] ==
'0' &&
955 ourmsg->
data[hupos + 1] ==
'x' && hulen % 2 == 0) {
957 static const char hexdig[16] =
"0123456789abcdef";
961 for (i = 0; i < hulen - 2; i++) {
964 ourmsg->
data[hupos + 2 + i] != hexdig[j];
1011 LIST_INSERT_HEAD(&privp->listeners, sp, sessions);
1040 log(LOG_NOTICE,
"ng_pppoe[%x]: session not "
1041 "primed\n", node->
nd_ID);
1062 s = (
char *)msg->
data;
1075 privp->eh.ether_type =
1092 if (privp->flags == 0)
1103 s = (
char *)resp->
data;
1104 if (privp->flags == 0) {
1115 if (s != resp->
data)
1125 bcopy(msg->
data, &privp->eh.ether_shost,
1132 privp->max_payload.hdr.tag_len = htons(
sizeof(uint16_t));
1133 privp->max_payload.data = htons(*((uint16_t *)msg->
data));
1140 m = m_gethdr(M_NOWAIT, MT_DATA);
1142 log(LOG_NOTICE,
"ng_pppoe[%x]: session out of "
1143 "mbufs\n", node->
nd_ID);
1150 bcopy(&sp->
pkt_hdr, wh,
sizeof(*wh));
1158 if (wh->
eh.ether_type ==
1166 tag = (
void *)(&wh->
ph + 1);
1169 strncpy((
char *)(tag + 1), ourmsg->
data, ourmsg->
data_len);
1170 m->m_pkthdr.len = m->m_len =
sizeof(*wh) +
sizeof(*tag) +
1173 NET_EPOCH_ENTER(et);
1175 privp->ethernet_hook, m);
1185 m = m_gethdr(M_NOWAIT, MT_DATA);
1187 log(LOG_NOTICE,
"ng_pppoe[%x]: session out of "
1188 "mbufs\n", node->
nd_ID);
1195 bcopy(&sp->
pkt_hdr, wh,
sizeof(*wh));
1203 if (wh->
eh.ether_type ==
1211 tag = (
void *)(&wh->
ph + 1);
1214 strncpy((
char *)(tag + 1), ourmsg->
data, ourmsg->
data_len);
1215 m->m_pkthdr.len = m->m_len =
sizeof(*wh) +
sizeof(*tag) +
1218 NET_EPOCH_ENTER(et);
1220 privp->ethernet_hook, m);
1236 bcopy(msg->
data, &privp->eh.ether_shost,
1249 CTR2(KTR_NET,
"%20s: returning %d", __func__, error);
1273 CTR2(KTR_NET,
"%20s: called %d", __func__, sp->
Session_ID);
1280 sizeof(
struct ether_header));
1285 if (privp->max_payload.data != 0)
1294 m0 = m_copypacket(neg->
m, M_NOWAIT);
1305 CTR2(KTR_NET,
"%20s: called %d", __func__, sp->
Session_ID);
1314 strncpy(sts->
hook, (
const char *)(tag + 1), tlen);
1315 sts->
hook[tlen] =
'\0';
1327 CTR2(KTR_NET,
"%20s: called %d", __func__, sp->
Session_ID);
1330 sizeof(uint16_t), M_NOWAIT);
1347 CTR2(KTR_NET,
"%20s: called %d", __func__, sp->
Session_ID);
1369 CTR2(KTR_NET,
"%20s: called %d", __func__, sp->
Session_ID);
1378 strncpy(padm->
msg, (
const char *)(tag + 1), tlen);
1379 padm->
msg[tlen] =
'\0';
1392 CTR2(KTR_NET,
"%20s: called %d", __func__, sp->
Session_ID);
1401 strncpy(padm->
msg, (
const char *)(tag + 1), tlen);
1402 padm->
msg[tlen] =
'\0';
1421 CTR6(KTR_NET,
"%20s: node [%x] (%p) received %p on \"%s\" (%p)",
1422 __func__, node->
nd_ID, node, item, hook->
hk_name, hook);
1425 switch (sp->
state) {
1434 if (m->m_pkthdr.len >= 2) {
1435 if (m->m_len < 2 && !(m = m_pullup(m, 2)))
1437 if (mtod(m, u_char *)[0] == 0xff &&
1438 mtod(m, u_char *)[1] == 0x03)
1445 M_PREPEND(m,
sizeof(*wh), M_NOWAIT);
1450 bcopy(&sp->
pkt_hdr, wh,
sizeof(*wh));
1451 wh->
ph.
length = htons(m->m_pkthdr.len -
sizeof(*wh));
1453 privp->packets_out++;
1472 if (m->m_len <
sizeof(*wh)) {
1473 m = m_pullup(m,
sizeof(*wh));
1492 bcopy(wh->
eh.ether_shost,
1503 uniqtag.hdr.tag_len = htons((u_int16_t)
sizeof(sp));
1504 uniqtag.data.pointer = sp;
1516 if (((tag == NULL) || (tag->
tag_len == 0)) &&
1531 m0 = m_copypacket(sp->
neg->
m, M_NOWAIT);
1533 privp->packets_out++;
1560 const struct pppoe_tag *utag = NULL, *tag = NULL;
1572 CTR6(KTR_NET,
"%20s: node [%x] (%p) received %p on \"%s\" (%p)",
1573 __func__, node->
nd_ID, node, item, hook->
hk_name, hook);
1580 privp->packets_in++;
1581 if( m->m_len <
sizeof(*wh)) {
1582 m = m_pullup(m,
sizeof(*wh));
1584 log(LOG_NOTICE,
"ng_pppoe[%x]: couldn't "
1585 "m_pullup(wh)\n", node->
nd_ID);
1591 switch(wh->
eh.ether_type) {
1600 if (m->m_pkthdr.len <= MHLEN) {
1601 if( m->m_len < m->m_pkthdr.len) {
1602 m = m_pullup(m, m->m_pkthdr.len);
1604 log(LOG_NOTICE,
"ng_pppoe[%x]: "
1605 "couldn't m_pullup(pkthdr)\n",
1611 if (m->m_len != m->m_pkthdr.len) {
1618 n = m_dup(m, M_NOWAIT);
1623 if (m->m_len != m->m_pkthdr.len) {
1629 log(LOG_NOTICE,
"ng_pppoe[%x]: packet "
1630 "fragmented\n", node->
nd_ID);
1659 if (sendhook != NULL)
1662 ntohs(tag->tag_len) == 0)
1665 error = ENETUNREACH;
1676 log(LOG_NOTICE,
"ng_pppoe[%x]: no host "
1677 "unique field\n", node->
nd_ID);
1682 if (sendhook == NULL) {
1683 log(LOG_NOTICE,
"ng_pppoe[%x]: no "
1684 "matching session\n", node->
nd_ID);
1698 log(LOG_NOTICE,
"ng_pppoe[%x]: session "
1699 "in wrong state\n", node->
nd_ID);
1712 (
const char *)(tag + 1),
1726 bcopy(wh->
eh.ether_shost,
1740 (privp->max_payload.data != 0))
1750 m0 = m_copypacket(neg->
m, M_NOWAIT);
1760 if ((utag == NULL) ||
1761 (ntohs(utag->
tag_len) !=
sizeof(sp))) {
1766 if (sendhook == NULL)
1783 LEAVE (ENETUNREACH);
1808 m0 = m_copypacket(sp->
neg->
m, M_NOWAIT);
1842 LEAVE (ENETUNREACH);
1845 if (sendhook == NULL)
1880 (privp->max_payload.data != 0))
1901 LEAVE (ENETUNREACH);
1908 LEAVE(EPFNOSUPPORT);
1918 LEAVE (ENETUNREACH);
1919 m_adj(m,
sizeof(*wh));
1922 if (m->m_pkthdr.len <
length)
1925 if (m->m_pkthdr.len >
length) {
1926 m_adj(m, -((
int)(m->m_pkthdr.len -
length)));
1937 m_freem(sp->
neg->
m);
1942 LEAVE (ENETUNREACH);
1948 LEAVE(EPFNOSUPPORT);
1967 CTR6(KTR_NET,
"%20s: node [%x] (%p) received %p on \"%s\" (%p)",
1968 __func__, node->
nd_ID, node, item, hook->
hk_name, hook);
1971 privp->packets_out++;
1987 mtx_destroy(&privp->sesshash[i].mtx);
2007 if (hook == privp->debug_hook) {
2008 privp->debug_hook = NULL;
2009 }
else if (hook == privp->ethernet_hook) {
2010 privp->ethernet_hook = NULL;
2023 if ((privp->ethernet_hook)
2029 m = m_gethdr(M_NOWAIT, MT_DATA);
2031 log(LOG_NOTICE,
"ng_pppoe[%x]: session out of "
2032 "mbufs\n", node->
nd_ID);
2034 struct epoch_tracker et;
2041 bcopy(&sp->
pkt_hdr, wh,
sizeof(*wh));
2049 if (wh->
eh.ether_type ==
2058 tag = (
void *)(&wh->
ph + 1);
2060 tag->
tag_len = htons((u_int16_t)msglen);
2061 strncpy((
char *)(tag + 1),
SIGNOFF, msglen);
2062 m->m_pkthdr.len = m->m_len =
sizeof(*wh) +
sizeof(*tag) +
2064 wh->
ph.
length = htons(
sizeof(*tag) + msglen);
2066 NET_EPOCH_ENTER(et);
2068 privp->ethernet_hook, m);
2073 LIST_REMOVE(sp, sessions);
2083 m_freem(sp->
neg->
m);
2104 struct mbuf *m0 = NULL;
2107 CTR6(KTR_NET,
"%20s: node [%x] (%p) hook \"%s\" (%p) session %d",
2118 m0 = m_copypacket(sp->
neg->
m, M_NOWAIT);
2138 log(LOG_NOTICE,
"ng_pppoe[%x]: unexpected timeout\n",
2151 const char *
const end = (
const char *)
next_tag(ph);
2153 const struct pppoe_tag *pt = (
const void *)(ph + 1);
2158 CTR2(KTR_NET,
"%20s: called %d", __func__, sp->
Session_ID);
2160 while((
const char*)(pt + 1) <= end) {
2164 ptn = (((
const char *)(pt + 1)) + ntohs(pt->
tag_len));
2199 CTR2(KTR_NET,
"%20s: called %d", __func__, sp->
Session_ID);
int ng_connect_t(hook_p hook)
#define NG_HOOK_NODE(hook)
#define NG_PEER_NODE(hook)
int ng_rcvmsg_t(node_p node, item_p item, hook_p lasthook)
#define NG_FWD_ITEM_HOOK(error, item, hook)
int ng_disconnect_t(hook_p hook)
#define NG_NODE_SET_PRIVATE(node, val)
#define NG_RESPOND_MSG(error, here, item, resp)
#define NG_NODE_IS_VALID(node)
int ng_rmhook_self(hook_p hook)
#define NG_NODE_UNREF(node)
#define NG_HOOK_SET_PRIVATE(hook, val)
int ng_rmnode_self(node_p here)
#define ng_callout_init(c)
#define NG_FWD_NEW_DATA(error, item, hook, m)
#define NG_SEND_DATA_ONLY(error, hook, m)
#define NG_SEND_MSG_ID(error, here, msg, ID, retaddr)
int ng_rcvdata_t(hook_p hook, item_p item)
int ng_shutdown_t(node_p node)
int ng_uncallout(struct callout *c, node_p node)
#define NG_HOOK_NAME(hook)
#define NG_FREE_ITEM(item)
#define NG_HOOK_SET_RCVDATA(hook, val)
int ng_constructor_t(node_p node)
#define NG_NODE_NUMHOOKS(node)
#define NGI_GET_MSG(i, m)
#define NG_NODE_PRIVATE(node)
int ng_callout(struct callout *c, node_p node, hook_p hook, int ticks, ng_item_fn *fn, void *arg1, int arg2)
int ng_newhook_t(node_p node, hook_p hook, const char *name)
hook_p ng_findhook(node_p node, const char *name)
#define NG_HOOK_PRIVATE(hook)
MALLOC_DEFINE(M_NG_CCATM, "ng_ccatm", "netgraph uni api node")
struct cisco_header __packed
#define NG_MKRESPONSE(rsp, msg, len, how)
#define NG_MKMESSAGE(msg, cookie, cmdid, len, how)
const struct ng_parse_type ng_parse_uint16_type
const struct ng_parse_type ng_parse_enaddr_type
const struct ng_parse_type ng_parse_string_type
const struct ng_parse_type ng_parse_struct_type
static hook_p pppoe_findcookie(node_p node, const struct pppoe_tag *tag)
static const struct ng_parse_type ngpppoe_init_data_state_type
static ng_connect_t ng_pppoe_connect
static void init_tags(sessp sp)
static ng_shutdown_t ng_pppoe_shutdown
static hook_p pppoe_finduniq(node_p node, const struct pppoe_tag *tag)
NETGRAPH_INIT(pppoe, &typestruct)
static int send_hurl(sessp sp, const struct pppoe_tag *tag)
static const struct ng_cmdlist ng_pppoe_cmds[]
static hook_p pppoe_find_svc(node_p node, const char *svc_name, int svc_len)
static ng_rcvdata_t ng_pppoe_rcvdata_ether
static ng_disconnect_t ng_pppoe_disconnect
static ng_constructor_t ng_pppoe_constructor
static sessp pppoe_findsession(priv_p privp, const struct pppoe_full_hdr *wh)
static int send_sessionid(sessp sp)
static void make_packet(sessp sp)
static void insert_tag(sessp sp, const struct pppoe_tag *tp)
static int pppoe_broadcast_padi(node_p node, struct mbuf *m0)
static const struct pppoe_tag * scan_tags(sessp sp, const struct pppoe_hdr *ph)
static int pppoe_send_event(sessp sp, enum cmd cmdid)
static struct ng_type typestruct
static int send_acname(sessp sp, const struct pppoe_tag *tag)
static int send_maxp(sessp sp, const struct pppoe_tag *tag)
static const struct ng_parse_struct_field ng_pppoe_sts_type_fields[]
static const struct ng_parse_type ng_pppoe_sts_state_type
static ng_rcvmsg_t ng_pppoe_rcvmsg
static const struct ng_parse_struct_field ngpppoe_init_data_type_fields[]
static int send_motm(sessp sp, const struct pppoe_tag *tag)
static const struct pppoe_tag * get_tag(const struct pppoe_hdr *ph, uint16_t idx)
static __inline const struct pppoe_tag * next_tag(const struct pppoe_hdr *ph)
static hook_p pppoe_match_svc(node_p node, const struct pppoe_tag *tag)
static ng_newhook_t ng_pppoe_newhook
static void pppoe_addsession(sessp sp)
static ng_rcvdata_t ng_pppoe_rcvdata
static void pppoe_start(sessp sp)
static uint16_t pppoe_getnewsession(sessp sp)
static void pppoe_ticker(node_p node, hook_p hook, void *arg1, int arg2)
static ng_rcvdata_t ng_pppoe_rcvdata_debug
static void pppoe_delsession(sessp sp)
#define ETHERTYPE_PPPOE_3COM_SESS
#define NG_PPPOE_HOOK_ETHERNET
#define NG_PPPOE_STS_TYPE_INFO
#define ETHERTYPE_PPPOE_3COM_DISC
#define ETHERTYPE_PPPOE_SESS
#define PPPOE_TIMEOUT_LIMIT
#define PPPOE_SERVICE_NAME_SIZE
#define NG_PPPOE_INIT_DATA_TYPE_INFO
#define NG_PPPOE_STANDARD
#define NG_PPPOE_HOOK_DEBUG
#define PPPOE_OFFER_TIMEOUT
#define NG_PPPOE_NODE_TYPE
#define ETHERTYPE_PPPOE_DISC
#define PPPOE_PADM_VALUE_SIZE
#define PPPOE_INITIAL_TIMEOUT
static LIST_HEAD(ngatm_msg)
u_int8_t data[PPPOE_SERVICE_NAME_SIZE]
struct ng_mesg::ng_msghdr header
char msg[PPPOE_PADM_VALUE_SIZE]
struct pppoe_full_hdr pkt_hdr
const struct pppoe_tag * tags[NUMTAGS]
struct pppoe_full_hdr pkt_header
char bytes[sizeof(void *)]