summaryrefslogtreecommitdiffstats
path: root/sys/netgraph/ng_pppoe.c
diff options
context:
space:
mode:
authorglebius <glebius@FreeBSD.org>2004-07-27 19:47:13 +0000
committerglebius <glebius@FreeBSD.org>2004-07-27 19:47:13 +0000
commit1a3245e3ca370fa98c56cc95489502e21729ea3b (patch)
treed9b10c920b8a87413f553c675b6c254edaf73a0e /sys/netgraph/ng_pppoe.c
parent1a23ddfc9e22a542953d1a0b8984b35ea9760dcf (diff)
downloadFreeBSD-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
Diffstat (limited to 'sys/netgraph/ng_pppoe.c')
-rw-r--r--sys/netgraph/ng_pppoe.c153
1 files changed, 111 insertions, 42 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;
OpenPOWER on IntegriCloud