diff options
author | glebius <glebius@FreeBSD.org> | 2004-07-27 19:47:13 +0000 |
---|---|---|
committer | glebius <glebius@FreeBSD.org> | 2004-07-27 19:47:13 +0000 |
commit | 1a3245e3ca370fa98c56cc95489502e21729ea3b (patch) | |
tree | d9b10c920b8a87413f553c675b6c254edaf73a0e | |
parent | 1a23ddfc9e22a542953d1a0b8984b35ea9760dcf (diff) | |
download | FreeBSD-src-1a3245e3ca370fa98c56cc95489502e21729ea3b.zip FreeBSD-src-1a3245e3ca370fa98c56cc95489502e21729ea3b.tar.gz |
When node is server serve both standard RFC2516 and non-standard 3Com
clients simultaneously. When node is client its mode is configured
with a control message.
sysctl net.graph.nonstandard_pppoe is deprecated but kept for
backward compatibility for some time.
Approved by: julian
-rw-r--r-- | sys/netgraph/ng_pppoe.c | 153 | ||||
-rw-r--r-- | sys/netgraph/ng_pppoe.h | 10 |
2 files changed, 119 insertions, 44 deletions
diff --git a/sys/netgraph/ng_pppoe.c b/sys/netgraph/ng_pppoe.c index 8396e8d..4a29a71 100644 --- a/sys/netgraph/ng_pppoe.c +++ b/sys/netgraph/ng_pppoe.c @@ -151,6 +151,20 @@ static const struct ng_cmdlist ng_pppoe_cmds[] = { &ng_pppoe_sts_state_type, NULL }, + { + NGM_PPPOE_COOKIE, + NGM_PPPOE_SETMODE, + "pppoe_setmode", + &ng_parse_string_type, + NULL + }, + { + NGM_PPPOE_COOKIE, + NGM_PPPOE_GETMODE, + "pppoe_getmode", + NULL, + &ng_parse_string_type + }, { 0 } }; @@ -224,6 +238,35 @@ struct sess_con { }; typedef struct sess_con *sessp; +#define NG_PPPOE_SESSION_NODE(sp) NG_HOOK_NODE(sp->hook) + +enum { + PPPOE_STANDARD = 1, /* standard RFC2516 mode */ + PPPOE_NONSTANDARD, /* 3Com proprietary mode */ +}; + +struct ng_pppoe_mode_t { + u_int8_t id; + const struct ether_header *eh_prototype; + const char *name; +}; + +static const struct ether_header eh_standard = + {{0xff,0xff,0xff,0xff,0xff,0xff}, + {0x00,0x00,0x00,0x00,0x00,0x00}, + ETHERTYPE_PPPOE_DISC}; + +static const struct ether_header eh_3Com = + {{0xff,0xff,0xff,0xff,0xff,0xff}, + {0x00,0x00,0x00,0x00,0x00,0x00}, + ETHERTYPE_PPPOE_STUPID_DISC}; + +static const struct ng_pppoe_mode_t ng_pppoe_modes[] = { + { PPPOE_STANDARD, &eh_standard, NG_PPPOE_STANDARD }, + { PPPOE_NONSTANDARD, &eh_3Com, NG_PPPOE_NONSTANDARD }, + { 0, NULL}, +}; + /* * Information we store for each node */ @@ -234,23 +277,17 @@ struct PPPOE { u_int packets_in; /* packets in from ethernet */ u_int packets_out; /* packets out towards ethernet */ u_int32_t flags; + const struct ng_pppoe_mode_t *mode; /* standard PPPoE or 3Com? */ /*struct sess_con *buckets[HASH_SIZE];*/ /* not yet used */ }; typedef struct PPPOE *priv_p; -/* - * XXXRW: Leave this unsynchronized, since only a single field is modified, - * and it's done so infrequently. Likewise, pppoe_mode. - */ -struct ether_header eh_prototype = - {{0xff,0xff,0xff,0xff,0xff,0xff}, - {0x00,0x00,0x00,0x00,0x00,0x00}, - ETHERTYPE_PPPOE_DISC}; - -#define PPPOE_KEEPSTANDARD -1 /* never switch to nonstandard mode */ -#define PPPOE_STANDARD 0 /* try standard mode (dangerous!) */ -#define PPPOE_NONSTANDARD 1 /* just be in nonstandard mode */ +/* Deprecated sysctl, leaved here to keep compatibility for some time */ +#define PPPOE_KEEPSTANDARD -1 +#define PPPOE_STANDARD 0 +#define PPPOE_NONSTANDARD 1 static int pppoe_mode = PPPOE_KEEPSTANDARD; +static const struct ng_pppoe_mode_t *sysctl_mode = ng_pppoe_modes; static int ngpppoe_set_ethertype(SYSCTL_HANDLER_ARGS) @@ -264,20 +301,18 @@ ngpppoe_set_ethertype(SYSCTL_HANDLER_ARGS) return (error); switch (val) { case PPPOE_NONSTANDARD: - pppoe_mode = PPPOE_NONSTANDARD; - eh_prototype.ether_type = ETHERTYPE_PPPOE_STUPID_DISC; + sysctl_mode = ng_pppoe_modes + 1; break; case PPPOE_STANDARD: - pppoe_mode = PPPOE_STANDARD; - eh_prototype.ether_type = ETHERTYPE_PPPOE_DISC; - break; case PPPOE_KEEPSTANDARD: - pppoe_mode = PPPOE_KEEPSTANDARD; - eh_prototype.ether_type = ETHERTYPE_PPPOE_DISC; + sysctl_mode = ng_pppoe_modes; break; default: return (EINVAL); } + + pppoe_mode = val; + printf("net.graph.nonstandard_pppoe is deprecated. See ng_pppoe(4), ppp(8).\n"); return (0); } @@ -600,6 +635,10 @@ AAA /* Link structs together; this counts as our one reference to *nodep */ NG_NODE_SET_PRIVATE(node, privdata); privdata->node = node; + + /* Initialize to standard mode (the first one in ng_pppoe_modes[]). */ + privdata->mode = sysctl_mode; + return (0); } @@ -757,7 +796,9 @@ AAA callout_handle_init( &neg->timeout_handle); neg->m->m_len = sizeof(struct pppoe_full_hdr); neg->pkt = mtod(neg->m, union packet*); - neg->pkt->pkt_header.eh = eh_prototype; + memcpy((void *)&neg->pkt->pkt_header.eh, + (const void *)privp->mode->eh_prototype, + sizeof(struct ether_header)); neg->pkt->pkt_header.ph.ver = 0x1; neg->pkt->pkt_header.ph.type = 0x1; neg->pkt->pkt_header.ph.sid = 0x0000; @@ -860,6 +901,38 @@ AAA ourmsg->data_len); neg->service_len = ourmsg->data_len; break; + case NGM_PPPOE_SETMODE: + { + const struct ng_pppoe_mode_t *mode; + char *s; + size_t len; + + if (msg->header.arglen == 0) + LEAVE(EINVAL); + + s = (char *)msg->data; + len = msg->header.arglen - 1; + + /* Search for matching mode string */ + for (mode = ng_pppoe_modes; mode->id != 0; mode++ ) + if ((strlen(mode->name) == len) && + !strncmp(mode->name, s, len)) + break; /* found */ + + if (mode->id != 0) + privp->mode = mode; + else + LEAVE(EINVAL); + break; + } + case NGM_PPPOE_GETMODE: + NG_MKRESPONSE(resp, msg, strlen(privp->mode->name) + 1, + M_NOWAIT); + if (resp == NULL) + LEAVE(ENOMEM); + strlcpy((char *)resp->data, privp->mode->name, + strlen(privp->mode->name) + 1); + break; default: LEAVE(EINVAL); } @@ -883,6 +956,7 @@ quit: static void pppoe_start(sessp sp) { + priv_p privp = NG_NODE_PRIVATE(NG_PPPOE_SESSION_NODE(sp)); struct { struct pppoe_tag hdr; union uniq data; @@ -893,8 +967,11 @@ pppoe_start(sessp sp) */ AAA sp->state = PPPOE_SINIT; - /* reset the packet header to broadcast */ - sp->neg->pkt->pkt_header.eh = eh_prototype; + /* Reset the packet header to broadcast. Since we are in a client + * mode use configured ethertype. */ + memcpy((void *)&sp->neg->pkt->pkt_header.eh, + (const void *)privp->mode->eh_prototype, + sizeof(struct ether_header)); sp->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)); @@ -997,23 +1074,7 @@ AAA wh = mtod(m, struct pppoe_full_hdr *); length = ntohs(wh->ph.length); switch(wh->eh.ether_type) { - case ETHERTYPE_PPPOE_STUPID_DISC: - if (pppoe_mode == PPPOE_STANDARD) { - pppoe_mode = PPPOE_NONSTANDARD; - eh_prototype.ether_type = - ETHERTYPE_PPPOE_STUPID_DISC; - log(LOG_NOTICE, - "Switched to nonstandard PPPoE mode due to " - "packet from %*D\n", - ETHER_ADDR_LEN, - wh->eh.ether_shost, ":"); - } else if (pppoe_mode == PPPOE_KEEPSTANDARD) - log(LOG_NOTICE, - "Ignored nonstandard PPPoE packet " - "from %*D\n", - ETHER_ADDR_LEN, - wh->eh.ether_shost, ":"); - /* fall through */ + case ETHERTYPE_PPPOE_STUPID_DISC: /* fall through */ case ETHERTYPE_PPPOE_DISC: /* * We need to try to make sure that the tag area @@ -1214,7 +1275,10 @@ AAA * from NEWCONNECTED to CONNECTED */ sp->pkt_hdr = neg->pkt->pkt_header; - if (pppoe_mode == PPPOE_NONSTANDARD) + /* Configure ethertype depending on what + * ethertype was used at discovery phase */ + if (sp->pkt_hdr.eh.ether_type == + ETHERTYPE_PPPOE_STUPID_DISC) sp->pkt_hdr.eh.ether_type = ETHERTYPE_PPPOE_STUPID_SESS; else @@ -1266,7 +1330,7 @@ AAA * Keep a copy of the header we will be using. */ sp->pkt_hdr = neg->pkt->pkt_header; - if (pppoe_mode == PPPOE_NONSTANDARD) + if (privp->mode->id == PPPOE_NONSTANDARD) sp->pkt_hdr.eh.ether_type = ETHERTYPE_PPPOE_STUPID_SESS; else @@ -1407,6 +1471,8 @@ AAA session = ntohs(wh->ph.sid); length = ntohs(wh->ph.length); code = wh->ph.code; + /* Use peers mode in session */ + neg->pkt->pkt_header.eh.ether_type = wh->eh.ether_type; if ( code != PADI_CODE) { LEAVE(EINVAL); }; @@ -1548,7 +1614,10 @@ AAA /* revert the stored header to DISC/PADT mode */ wh = &sp->pkt_hdr; wh->ph.code = PADT_CODE; - if (pppoe_mode == PPPOE_NONSTANDARD) + /* Configure ethertype depending on what was used during + * sessions stage. */ + if (sp->pkt_hdr.eh.ether_type == + ETHERTYPE_PPPOE_STUPID_SESS) wh->eh.ether_type = ETHERTYPE_PPPOE_STUPID_DISC; else wh->eh.ether_type = ETHERTYPE_PPPOE_DISC; diff --git a/sys/netgraph/ng_pppoe.h b/sys/netgraph/ng_pppoe.h index 9e09d0c..892d655 100644 --- a/sys/netgraph/ng_pppoe.h +++ b/sys/netgraph/ng_pppoe.h @@ -49,7 +49,7 @@ /* Node type name. This should be unique among all netgraph node types */ #define NG_PPPOE_NODE_TYPE "pppoe" -#define NGM_PPPOE_COOKIE 939032003 +#define NGM_PPPOE_COOKIE 1089893072 /* Number of active sessions we can handle */ #define PPPOE_NUM_SESSIONS 16 /* for now */ @@ -62,6 +62,10 @@ #define NG_PPPOE_HOOK_C_LEADIN "client" /* Connect message starts this */ #define NG_PPPOE_HOOK_DEBUG "debug" +/* Mode names */ +#define NG_PPPOE_STANDARD "standard" +#define NG_PPPOE_NONSTANDARD "3Com" + /********************************************************************** * Netgraph commands understood by this node type. * FAIL, SUCCESS, CLOSE and ACNAME are sent by the node rather than received. @@ -77,7 +81,9 @@ enum cmd { NGM_PPPOE_SERVICE = 8, /* additional Service to advertise (in PADO) */ NGM_PPPOE_ACNAME = 9, /* AC_NAME for informational purposes */ NGM_PPPOE_GET_STATUS = 10, /* data in/out */ - NGM_PPPOE_SESSIONID = 11 /* Session_ID for informational purposes */ + NGM_PPPOE_SESSIONID = 11, /* Session_ID for informational purposes */ + NGM_PPPOE_SETMODE = 12, /* set to standard or 3Com mode */ + NGM_PPPOE_GETMODE = 13, /* see current mode */ }; /*********************** |