420 lines
14 KiB
Groff
420 lines
14 KiB
Groff
.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
|
|
.\" All rights reserved.
|
|
.\"
|
|
.\" Subject to the following obligations and disclaimer of warranty, use and
|
|
.\" redistribution of this software, in source or object code forms, with or
|
|
.\" without modifications are expressly permitted by Whistle Communications;
|
|
.\" provided, however, that:
|
|
.\" 1. Any and all reproductions of the source or object code must include the
|
|
.\" copyright notice above and the following disclaimer of warranties; and
|
|
.\" 2. No rights are granted, in any manner or form, to use Whistle
|
|
.\" Communications, Inc. trademarks, including the mark "WHISTLE
|
|
.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
|
|
.\" such appears in the above copyright notice or in the software.
|
|
.\"
|
|
.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
|
|
.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
|
|
.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
|
|
.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
|
|
.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
|
|
.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
|
|
.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
|
|
.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
|
|
.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
|
|
.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
|
|
.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
|
.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
|
|
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
|
|
.\" OF SUCH DAMAGE.
|
|
.\"
|
|
.\" Author: Archie Cobbs <archie@FreeBSD.org>
|
|
.\"
|
|
.\" $FreeBSD$
|
|
.\" $Whistle: ng_pppoe.8,v 1.1 1999/01/25 23:46:27 archie Exp $
|
|
.\"
|
|
.Dd October 28, 1999
|
|
.Dt NG_PPPOE 4
|
|
.Os
|
|
.Sh NAME
|
|
.Nm ng_pppoe
|
|
.Nd RFC 2516 PPPOE protocol netgraph node type
|
|
.Sh SYNOPSIS
|
|
.In net/ethernet.h
|
|
.In netgraph/ng_pppoe.h
|
|
.Sh DESCRIPTION
|
|
The
|
|
.Nm pppoe
|
|
node type performs the PPPoE protocol. It is used in conjunction with the
|
|
.Xr netgraph 4
|
|
extensions to the Ethernet framework to divert and inject Ethernet packets
|
|
to and from a PPP agent (which is not specified).
|
|
.Pp
|
|
The
|
|
.Dv 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
|
|
.Dv NGM_TEXT_STATUS
|
|
control message.
|
|
.Sh HOOKS
|
|
This node type supports the following hooks:
|
|
.Pp
|
|
.Bl -tag -width foobarbaz
|
|
.It Dv ethernet
|
|
The hook that should normally be connected to an Ethernet node.
|
|
.It Dv debug
|
|
Presently no use.
|
|
.It Dv [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.
|
|
.El
|
|
.Sh CONTROL MESSAGES
|
|
This node type supports the generic control messages, plus the following:
|
|
.Bl -tag -width foo
|
|
.It Dv NGM_PPPOE_GET_STATUS
|
|
This command returns status information in a
|
|
.Dv "struct ngpppoestat" :
|
|
.Bd -literal -offset 4n
|
|
struct ngpppoestat {
|
|
u_int packets_in; /* packets in from ethernet */
|
|
u_int packets_out; /* packets out towards ethernet */
|
|
};
|
|
.Ed
|
|
.It Dv NGM_TEXT_STATUS
|
|
This generic message returns is a human-readable version of the node status.
|
|
(not yet)
|
|
.It Dv NGM_PPPOE_CONNECT
|
|
Tell a nominated newly created hook that it's 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
|
|
.Dv ngpppoe_init_data
|
|
structure shown below.
|
|
.It Dv NGM_PPPOE_LISTEN
|
|
Tell a nominated newly created hook that it's session should enter
|
|
the state machine in a manner to become a server listener. 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 unmodified 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
|
|
.Dv ngpppoe_init_data
|
|
structure shown below.
|
|
.It Dv NGM_PPPOE_OFFER
|
|
Tell a nominated newly created hook that it's 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 LISTEN mode hook ( see above).
|
|
This is so
|
|
that information that is required for the session that is embedded in
|
|
the original session request packet, is made available to the state machine
|
|
that eventually answers the request. When the Session request packet is
|
|
received, the session negotiation will proceed.
|
|
This command uses the
|
|
.Dv ngpppoe_init_data
|
|
structure shown below.
|
|
.Pp
|
|
The three commands above use a common data structure:
|
|
.Bd -literal -offset 4n
|
|
struct ngpppoe_init_data {
|
|
char hook[NG_HOOKLEN + 1]; /* hook to monitor on */
|
|
u_int16_t data_len; /* service name length */
|
|
char data[0]; /* init data goes here */
|
|
};
|
|
.Ed
|
|
.It Dv NGM_PPPOE_SUCCESS
|
|
This command is sent to the node that started this session 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.
|
|
.It Dv NGM_NGM_PPPOE_FAIL
|
|
This command is sent to the node that started this session with one of the
|
|
above messages, and reports a state change. This message reports
|
|
failed Session negotiation. It uses the structure shown below, and
|
|
reports back the hook name corresponding to the failed session.
|
|
The hook will probably have been removed immediately after sending this message
|
|
.It Dv NGM_NGM_PPPOE_CLOSE
|
|
This command is sent to the node that started this session 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 immediately after sending this
|
|
message. At present this message is not yet used and a 'failed' message
|
|
will be received at closure instead.
|
|
.Pp
|
|
The three commands above use a common data structure:
|
|
.Bd -literal -offset 4n
|
|
struct ngpppoe_sts {
|
|
char hook[NG_HOOKLEN + 1]; /* hook associated with event session */
|
|
};
|
|
.Ed
|
|
.El
|
|
.Sh SHUTDOWN
|
|
This node shuts down upon receipt of a
|
|
.Dv NGM_SHUTDOWN
|
|
control message, when all session have been disconnected or when the
|
|
.Dv ethernet
|
|
hook is disconnected.
|
|
.Sh SYSCTLs
|
|
If you are one of the unfortunate people who have an ISP that
|
|
uses some "pppoe" equipment from (I believe) 3com, and who have to
|
|
use a different ethertype on pppoe packets
|
|
(hey why not change it from the standard for
|
|
no reason?) then after you have kldloaded or compiled in your pppoe node,
|
|
you may have to do the following sysctl:
|
|
.Bd -literal
|
|
(kldload netgraph)
|
|
(kldload ng_pppoe)
|
|
sysctl net.graph.stupid_isp=1
|
|
.Ed
|
|
.Pp
|
|
to enable the alternate ethertypes. Then phone your ISP and ask them
|
|
why you need to set option "stupid_isp" for you to be able to connect.
|
|
.Sh EXAMPLES
|
|
The following code uses
|
|
.Dv libnetgraph
|
|
to set up a
|
|
.Nm
|
|
node and connect it to both a socket node and an Ethernet node. It can handle
|
|
the case of when a
|
|
.Nm
|
|
node is already attached to the Ethernet. It then starts a client session.
|
|
.Bd -literal
|
|
#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 *sessname,
|
|
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_NODELEN + 1];
|
|
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 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_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: 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", pppoe_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);
|
|
}
|
|
/*
|
|
* Send it a message telling it to start up.
|
|
*/
|
|
bzero(&message, sizeof(message));
|
|
snprintf(message.idata.hook, sizeof(message.idata.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);
|
|
}
|
|
.Ed
|
|
.Sh SEE ALSO
|
|
.Xr netgraph 3 ,
|
|
.Xr netgraph 4 ,
|
|
.Xr ng_ppp 4 ,
|
|
.Xr ng_socket 4 ,
|
|
.Xr ngctl 8
|
|
.Rs
|
|
.%A L. Mamakos
|
|
.%A K. Lidl
|
|
.%A J. Evarts
|
|
.%A D. Carrel
|
|
.%A D. Simone
|
|
.%A R. Wheeler
|
|
.%T "A Method for transmitting PPP over Ethernet (PPPoE)"
|
|
.%O RFC 2516
|
|
.Re
|
|
.Sh HISTORY
|
|
The
|
|
.Nm
|
|
node type was implemented in
|
|
.Fx 4.0 .
|
|
.Sh AUTHORS
|
|
.An Julian Elischer Aq julian@FreeBSD.org
|