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 Eth
ernet */

u_int packets_out; /* packets out towards
Ethernet */
};
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 moni
tor on */

u_int16_t data_len; /* service name
length */

char data[0]; /* init data goes
here */
};
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 with
event 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 a
session encapsulating packets into incorrect 3Com ethertypes.
This compatibility option doesn't affect server mode. In
server mode

ng_pppoe supports both modes simultaneously, de
pending on the

ethertype, the client used when connecting.
"D-Link"
When ng_pppoe is a PPPoE server serving only spe
cific ServiceName(s), it will respond to a PADI requests with
empty ServiceName tag, returning all available Service-Name(s)
on node.

This option is necessary for compatibility with D
Link DI-614+

and DI-624+ SOHO routers as clients, when serving
only specific

Service-Name. This compatibility option doesn't
affect 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 ask
ing 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 each
hook.

* 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 skip
making one

* ourself, but we continue, using

* the existing one.

*/
sprintf(pppoe_node_name, "[%08x]:",
peer->id);
} else {
/*
* There is already someone hogging
the data,

* return an error. Some day we'll
try

* daisy-chaining..

*/
return (EBUSY);
}
} else {

/*
* Try make a node of type PPPoE against
node "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_GENER
IC_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: The
PPPoE

* node is addressed as pppoe_node_name: attach to
it.

* Connect socket node to specified node Use the
same 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_NONSTAN
DARD,

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.ida
ta.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
Copyright © 2010-2025 Platon Technologies, s.r.o.           Home | Man pages | tLDP | Documents | Utilities | About
Design by styleshout