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