ng_pppoe(4)
NAME
ng_pppoe - RFC 2516 PPPoE protocol netgraph node type
SYNOPSIS
#include <sys/types.h> #include <net/ethernet.h> #include <netgraph.h> #include <netgraph/ng_pppoe.h>
DESCRIPTION
- The pppoe node type performs the PPPoE protocol. It is used
- in conjunction with the netgraph(4) extensions to the Ethernet frame
- work to divert
and inject Ethernet packets to and from a PPP agent (which - is not specified).
- The NGM_PPPOE_GET_STATUS control message can be used at any
- time to query
the current status of the PPPoE module. The only statistics - presently
available are the total packet counts for input and output. - This node
does not yet support the NGM_TEXT_STATUS control message.
HOOKS
This node type supports the following hooks:
- ethernet The hook that should normally be connected to
- an Ethernet
- node.
- debug Presently no use.
- [unspecified] Any other name is assumed to be a session
- hook that will
- be connected to a PPP client agent, or a PPP
- server agent.
CONTROL MESSAGES
- This node type supports the generic control messages, plus
- the following:
- NGM_PPPOE_GET_STATUS
- This command returns status information in a struct
- ngpppoestat:
struct ngpppoestat {u_int packets_in; /* packets in from Ethernet */
u_int packets_out; /* packets out towardsEthernet */}; - NGM_TEXT_STATUS
- This generic message returns is a human-readable ver
- sion of the node
status. (not yet) - NGM_PPPOE_CONNECT
- Tell a nominated newly created hook that its session
- should enter
the state machine in a manner to become 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. A session request packet will be broadcast on - the Ethernet.
This command uses the ngpppoe_init_data structure shown - below.
- NGM_PPPOE_LISTEN
- Tell a nominated newly created hook that its session
- should enter
the state machine in a manner to become a server lis - tener. The
argument given is the name of the service to listen on - behalf of a
zero length service length will match all requests for - service. A
matching service request packet will be passed unmodi - fied back to
the process responsible for starting the service. It - can then examine it and pass it on to the session that is started to
- answer the
request. This command uses the ngpppoe_init_data - structure shown
below. - NGM_PPPOE_OFFER
- Tell a nominated newly created hook that its session
- should enter
the state machine in a manner to become a server. The - argument
given is the name of the service to offer. A zero - length service is
legal. The State machine will progress to a state - where it will
await a request packet to be forwarded to it from the - startup
server, which in turn probably received it from a LIS - TEN mode hook (
see above). This is so that information that is re - quired for the
session that is embedded in the original session re - quest packet, is
made available to the state machine that eventually an - swers the
request. When the Session request packet is received, - the session
negotiation will proceed. This command uses the ngpp - poe_init_data
structure shown below. - The three commands above use a common data structure:
struct ngpppoe_init_data {char hook[NG_HOOKSIZ]; /* hook to monitor on */
u_int16_t data_len; /* service namelength */
char data[0]; /* init data goeshere */- };
- NGM_PPPOE_SUCCESS
- This command is sent to the node that started this ses
- sion with one
of the above messages, and reports a state change. - This message
reports successful Session negotiation. It uses the - structure shown
below, and reports back the hook name corresponding to - the successful session.
- NGM_NGM_PPPOE_FAIL
- This command is sent to the node that started this ses
- sion with one
of the above messages, and reports a state change. - This message
reports failed Session negotiation. It uses the struc - ture shown
below, and reports back the hook name corresponding to - the failed
session. The hook will probably have been removed im - mediately after
sending this message - NGM_NGM_PPPOE_CLOSE
- This command is sent to the node that started this ses
- sion with one
of the above messages, and reports a state change. - This message
reports a request to close a session. It uses the - structure shown
below, and reports back the hook name corresponding to - the closed
session. The hook will probably have been removed im - mediately after
sending this message. At present this message is not - yet used and a
'failed' message will be received at closure instead. - NGM_PPPOE_ACNAME
- This command is sent to the node that started this ses
- sion with one
of the above messages, and reports the Access Concen - trator Name.
- The four commands above use a common data structure:
struct ngpppoe_sts {char hook[NG_HOOKSIZ]; /* hook associated withevent session */- };
- NGM_PPPOE_GETMODE
- This command returns the current compatibility mode of
- the node as a
string. ASCII form of this message is "pppoe_getmode". - The following keywords are can be returned:
- "standard"
The node operates according to RFC 2516.
- "3Com"
When ng_pppoe is a PPPoE client, it initiates asession encapsulating packets into incorrect 3Com ethertypes.This compatibility option doesn't affect server mode. Inserver mode
ng_pppoe supports both modes simultaneously, depending on the
ethertype, the client used when connecting. - "D-Link"
When ng_pppoe is a PPPoE server serving only specific ServiceName(s), it will respond to a PADI requests withempty ServiceName tag, returning all available Service-Name(s)on node.
This option is necessary for compatibility with DLink DI-614+
and DI-624+ SOHO routers as clients, when servingonly specific
Service-Name. This compatibility option doesn'taffect client
mode. - NGM_PPPOE_SETMODE
- Configure node to the specified mode. The string argu
- ment is
required. This command understands same keywords, that - are returned
by NGM_PPPOE_GETMODE command. ASCII form of this mes - sage is
"pppoe_setmode". For example, the following command - will configure
the node to initiate the next session in the propri - etary 3Com mode:
ngctl msg fxp0:orphans pppoe_setmode '"3Com"'
SHUTDOWN
- This node shuts down upon receipt of a NGM_SHUTDOWN control
- message, when
all session have been disconnected or when the ethernet hook - is disconnected.
EXAMPLES
- The following code uses libnetgraph to set up a ng_pppoe
- node and connect
it to both a socket node and an Ethernet node. It can han - dle the case of
when a ng_pppoe node is already attached to the Ethernet. - It then starts
a client session. - #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sysexits.h>
#include <errno.h>
#include <err.h> - #include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <net/ethernet.h> - #include <netgraph.h>
#include <netgraph/ng_ether.h>
#include <netgraph/ng_pppoe.h>
#include <netgraph/ng_socket.h>
static int setup(char *ethername, char *service, char *sess - name,
- int *dfd, int *cfd);
- int
main()
{ - int fd1, fd2;
setup("xl0", NULL, "fred", &fd1, &fd2);
sleep (30); - }
- static int
setup(char *ethername, char *service, char *sessname, - int *dfd, int *cfd)
- {
- struct ngm_connect ngc; /* connect */
struct ngm_mkpeer mkp; /* mkpeer */
/******** nodeinfo stuff **********/
u_char rbuf[2 * 1024];
struct ng_mesg *const resp = (struct ng_mesg *) - rbuf;
struct hooklist *const hlist= (struct hooklist *) resp->data; - struct nodeinfo *const ninfo = &hlist->nodeinfo;
int ch, no_hooks = 0;
struct linkinfo *link;
struct nodeinfo *peer;
/****message to connect PPPoE session*****/
struct {struct ngpppoe_init_data idata;
char service[100]; - } message;
/********tracking our little graph ********/
char path[100];
char source_ID[NG_NODESIZ];
char pppoe_node_name[100];
int k; - /*
* Create the data and control sockets
*/ - if (NgMkSockNode(NULL, cfd, dfd) < 0) {
return (errno);
- }
/** find the ether node of the name requested by asking it for
* it's inquiry information.
*/ - if (strlen(ethername) > 16)
return (EINVAL);
- sprintf(path, "%s:", ethername);
if (NgSendMsg(*cfd, path, NGM_GENERIC_COOKIE,NGM_LISTHOOKS, NULL, 0) < 0) { - return (errno);
- }
/* - * the command was accepted so it exists. Await the
- reply (It's
* almost certainly already waiting).
*/ - if (NgRecvMsg(*cfd, resp, sizeof(rbuf), NULL) < 0) {
- return (errno);
- }
/** - * The following is available about the node:
* ninfo->name (string)
* ninfo->type (string)
* ninfo->id (u_int32_t)
* ninfo->hooks (u_int32_t) (count of hooks)
* check it is the correct type. and get it's ID for - use
* with mkpeer later.
*/ - if (strncmp(ninfo->type, NG_ETHER_NODE_TYPE,
- strlen(NG_ETHER_NODE_TYPE)) != 0) {
- return (EPROTOTYPE);
- }
sprintf(source_ID, "[%08x]:", ninfo->id); - /*
- * look for a hook already attached.
*/ - for (k = 0; k < ninfo->hooks; k++) {
- /**
* The following are available about eachhook.
* link->ourhook (string)
* link->peerhook (string)
* peer->name (string)
* peer->type (string)
* peer->id (u_int32_t)
* peer->hooks (u_int32_t)
*/ - link = &hlist->link[k];
peer = &hlist->link[k].nodeinfo; - /* Ignore debug hooks */
if (strcmp("debug", link->ourhook) == 0)continue; - /* If the orphans hook is attached, use that
- */
if (strcmp(NG_ETHER_HOOK_ORPHAN, - link->ourhook) == 0) {
break;
- }
/* the other option is the 'divert' hook */
if (strcmp("NG_ETHER_HOOK_DIVERT",link->ourhook) == 0) {break;} - }
- /*
* See if we found a hook there.
*/ - if (k < ninfo->hooks) {
if (strcmp(peer->type, NG_PPPOE_NODE_TYPE)== 0) {/** If it's a type PPPoE, we skipmaking one
* ourself, but we continue, using
* the existing one.
*/sprintf(pppoe_node_name, "[%08x]:",peer->id);} else {/** There is already someone hoggingthe data,
* return an error. Some day we'lltry
* daisy-chaining..
*/return (EBUSY);} - } else {
/** Try make a node of type PPPoE againstnode "ID"
* On hook NG_ETHER_HOOK_ORPHAN.
*/snprintf(mkp.type, sizeof(mkp.type),"%s", NG_PPPOE_NODE_TYPE);snprintf(mkp.ourhook, sizeof(mkp.ourhook),"%s", NG_ETHER_HOOK_ORPHAN);snprintf(mkp.peerhook, sizeof(mkp.peerhook),"%s", NG_PPPOE_HOOK_ETHERNET);/* Send message */
if (NgSendMsg(*cfd, source_ID, NGM_GENERIC_COOKIE,NGM_MKPEER, &mkp, sizeof(mkp))< 0) {return (errno); - }
/** Work out a name for the new node.
*/ - sprintf(pppoe_node_name, "%s:%s",
source_ID, NG_ETHER_HOOK_ORPHAN);
- }
/** We now have a PPPoE node attached to the Ethernet
* card. The Ethernet is addressed as ethername: ThePPPoE
* node is addressed as pppoe_node_name: attach toit.
* Connect socket node to specified node Use thesame hook
* name on both ends of the link.
*/ - snprintf(ngc.path, sizeof(ngc.path), "%s", pp
- poe_node_name);
snprintf(ngc.ourhook, sizeof(ngc.ourhook), "%s", - sessname);
snprintf(ngc.peerhook, sizeof(ngc.peerhook), "%s", - sessname);
- if (NgSendMsg(*cfd, ".:", NGM_GENERIC_COOKIE,
NGM_CONNECT, &ngc, sizeof(ngc)) < 0) {
- return (errno);
- }
- #ifdef NONSTANDARD
- /*
* In some cases we are speaking to 3Com hardware,so
* configure node to non-standard mode.
*/ - if (NgSendMsg(*cfd, ngc.path, NGM_PPPOE_COOKIE,
NGM_PPPOE_SETMODE, NG_PPPOE_NONSTANDARD,
strlen(NG_PPPOE_NONSTANDARD) + 1) ==-1) { - return (errno);
- }
- #endif
/** Send it a message telling it to start up.
*/- bzero(&message, sizeof(message));
snprintf(message.idata.hook, sizeof(message.ida - ta.hook),
"%s", sessname);
- if (service == NULL) {
message.idata.data_len = 0;
- } else {
snprintf(message.idata.data,sizeof(message.idata.data), "%s",service);message.idata.data_len = strlen(service);
- }
/* Tell session/hook to start up as a client */
if (NgSendMsg(*cfd, ngc.path,NGM_PPPOE_COOKIE, NGM_PPPOE_CONNECT,&message.idata,
sizeof(message.idata) + message.idata.data_len) < 0) { - return (errno);
- }
return (0); - }
SEE ALSO
- netgraph(3), netgraph(4), ng_ppp(4), ng_socket(4), ngctl(8),
- ppp(8)
- L. Mamakos, K. Lidl, J. Evarts, D. Carrel, D. Simone, and R.
- Wheeler, A
Method for transmitting PPP over Ethernet (PPPoE), RFC 2516.
HISTORY
The ng_pppoe node type was implemented in FreeBSD 4.0.
AUTHORS
- Julian Elischer <julian@FreeBSD.org>
- BSD January 27, 2006