1.\" Copyright (c) 1996-1999 Whistle Communications, Inc. 2.\" All rights reserved. 3.\" 4.\" Subject to the following obligations and disclaimer of warranty, use and 5.\" redistribution of this software, in source or object code forms, with or 6.\" without modifications are expressly permitted by Whistle Communications; 7.\" provided, however, that: 8.\" 1. Any and all reproductions of the source or object code must include the 9.\" copyright notice above and the following disclaimer of warranties; and 10.\" 2. No rights are granted, in any manner or form, to use Whistle 11.\" Communications, Inc. trademarks, including the mark "WHISTLE 12.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as 13.\" such appears in the above copyright notice or in the software. 14.\" 15.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 16.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 17.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 18.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 19.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 20.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 21.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 22.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 23.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 24.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 25.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 26.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 27.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 28.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 31.\" OF SUCH DAMAGE. 32.\" 33.\" Author: Archie Cobbs <archie@FreeBSD.org> 34.\" 35.\" $FreeBSD: src/share/man/man4/ng_pppoe.4,v 1.18.2.1 2001/12/21 09:00:51 ru Exp $ 36.\" $Whistle: ng_pppoe.8,v 1.1 1999/01/25 23:46:27 archie Exp $ 37.\" 38.Dd October 28, 1999 39.Dt NG_PPPOE 4 40.Os 41.Sh NAME 42.Nm ng_pppoe 43.Nd RFC 2516 PPPOE protocol netgraph node type 44.Sh SYNOPSIS 45.In net/ethernet.h 46.In netgraph/pppoe/ng_pppoe.h 47.Sh DESCRIPTION 48The 49.Nm pppoe 50node type performs the PPPoE protocol. It is used in conjunction with the 51.Xr netgraph 4 52extensions to the Ethernet framework to divert and inject Ethernet packets 53to and from a PPP agent (which is not specified). 54.Pp 55The 56.Dv NGM_PPPOE_GET_STATUS 57control message can be used at any time to query the current status 58of the PPPOE module. The only statistics presently available are the 59total packet counts for input and output. This node does not yet support 60the 61.Dv NGM_TEXT_STATUS 62control message. 63.Sh HOOKS 64This node type supports the following hooks: 65.Bl -tag -width foobarbaz 66.It Dv ethernet 67The hook that should normally be connected to an Ethernet node. 68.It Dv debug 69Presently no use. 70.It Dv [unspecified] 71Any other name is assumed to be a session hook that will be connected to 72a PPP client agent, or a ppp server agent. 73.El 74.Sh CONTROL MESSAGES 75This node type supports the generic control messages, plus the following: 76.Bl -tag -width foo 77.It Dv NGM_PPPOE_GET_STATUS 78This command returns status information in a 79.Dv "struct ngpppoestat" : 80.Bd -literal -offset 4n 81struct ngpppoestat { 82 u_int packets_in; /* packets in from ethernet */ 83 u_int packets_out; /* packets out towards ethernet */ 84}; 85.Ed 86.It Dv NGM_TEXT_STATUS 87This generic message returns is a human-readable version of the node status. 88(not yet) 89.It Dv NGM_PPPOE_CONNECT 90Tell a nominated newly created hook that its session should enter 91the state machine in a manner to become a client. It must be newly created and 92a service name can be given as an argument. It is legal to specify a zero length 93service name. This is common on some DSL setups. A session request packet 94will be broadcast on the Ethernet. 95This command uses the 96.Dv ngpppoe_init_data 97structure shown below. 98.It Dv NGM_PPPOE_LISTEN 99Tell a nominated newly created hook that its session should enter 100the state machine in a manner to become a server listener. The argument 101given is the name of the service to listen on behalf of. A zero length service 102length will match all requests for service. A matching service request 103packet will be passed unmodified back to the process responsible 104for starting the service. It can then examine it and pass it on to 105the session that is started to answer the request. 106This command uses the 107.Dv ngpppoe_init_data 108structure shown below. 109.It Dv NGM_PPPOE_OFFER 110Tell a nominated newly created hook that its session should enter 111the state machine in a manner to become a server. The argument 112given is the name of the service to offer. A zero length service 113is legal. The State machine will progress to a state where it will await 114a request packet to be forwarded to it from the startup server, 115which in turn probably received it from a LISTEN mode hook ( see above). 116This is so 117that information that is required for the session that is embedded in 118the original session request packet, is made available to the state machine 119that eventually answers the request. When the Session request packet is 120received, the session negotiation will proceed. 121This command uses the 122.Dv ngpppoe_init_data 123structure shown below. 124.Pp 125The three commands above use a common data structure: 126.Bd -literal -offset 4n 127struct ngpppoe_init_data { 128 char hook[NG_HOOKSIZ]; /* hook to monitor on */ 129 u_int16_t data_len; /* service name length */ 130 char data[0]; /* init data goes here */ 131}; 132.Ed 133.It Dv NGM_PPPOE_SUCCESS 134This command is sent to the node that started this session with one of the 135above messages, and reports a state change. This message reports 136successful Session negotiation. It uses the structure shown below, and 137reports back the hook name corresponding to the successful session. 138.It Dv NGM_NGM_PPPOE_FAIL 139This command is sent to the node that started this session with one of the 140above messages, and reports a state change. This message reports 141failed Session negotiation. It uses the structure shown below, and 142reports back the hook name corresponding to the failed session. 143The hook will probably have been removed immediately after sending this message 144.It Dv NGM_NGM_PPPOE_CLOSE 145This command is sent to the node that started this session with one of the 146above messages, and reports a state change. This message reports 147a request to close a session. It uses the structure shown below, and 148reports back the hook name corresponding to the closed session. 149The hook will probably have been removed immediately after sending this 150message. At present this message is not yet used and a 'failed' message 151will be received at closure instead. 152.Pp 153The three commands above use a common data structure: 154.Bd -literal -offset 4n 155struct ngpppoe_sts { 156 char hook[NG_HOOKSIZ]; /* hook associated with event session */ 157}; 158.Ed 159.El 160.Sh SHUTDOWN 161This node shuts down upon receipt of a 162.Dv NGM_SHUTDOWN 163control message, when all session have been disconnected or when the 164.Dv ethernet 165hook is disconnected. 166.Sh EXAMPLES 167The following code uses 168.Dv libnetgraph 169to set up a 170.Nm 171node and connect it to both a socket node and an Ethernet node. It can handle 172the case of when a 173.Nm 174node is already attached to the Ethernet. It then starts a client session. 175.Bd -literal 176#include <stdio.h> 177#include <stdlib.h> 178#include <string.h> 179#include <ctype.h> 180#include <unistd.h> 181#include <sysexits.h> 182#include <errno.h> 183#include <err.h> 184 185#include <sys/types.h> 186#include <sys/socket.h> 187#include <sys/select.h> 188#include <net/ethernet.h> 189 190#include <netgraph.h> 191#include <netgraph/ng_ether.h> 192#include <netgraph/ng_pppoe.h> 193#include <netgraph/ng_socket.h> 194static int setup(char *ethername, char *service, char *sessname, 195 int *dfd, int *cfd); 196 197int 198main() 199{ 200 int fd1, fd2; 201 setup("xl0", NULL, "fred", &fd1, &fd2); 202 sleep (30); 203} 204 205static int 206setup(char *ethername, char *service, char *sessname, 207 int *dfd, int *cfd) 208{ 209 struct ngm_connect ngc; /* connect */ 210 struct ngm_mkpeer mkp; /* mkpeer */ 211 /******** nodeinfo stuff **********/ 212 u_char rbuf[2 * 1024]; 213 struct ng_mesg *const resp = (struct ng_mesg *) rbuf; 214 struct hooklist *const hlist 215 = (struct hooklist *) resp->data; 216 struct nodeinfo *const ninfo = &hlist->nodeinfo; 217 int ch, no_hooks = 0; 218 struct linkinfo *link; 219 struct nodeinfo *peer; 220 /****message to connect pppoe session*****/ 221 struct { 222 struct ngpppoe_init_data idata; 223 char service[100]; 224 } message; 225 /********tracking our little graph ********/ 226 char path[100]; 227 char source_ID[NG_NODESIZ]; 228 char pppoe_node_name[100]; 229 int k; 230 231 /* 232 * Create the data and control sockets 233 */ 234 if (NgMkSockNode(NULL, cfd, dfd) < 0) { 235 return (errno); 236 } 237 /* 238 * find the ether node of the name requested by asking it for 239 * its inquiry information. 240 */ 241 if (strlen(ethername) > 16) 242 return (EINVAL); 243 sprintf(path, "%s:", ethername); 244 if (NgSendMsg(*cfd, path, NGM_GENERIC_COOKIE, 245 NGM_LISTHOOKS, NULL, 0) < 0) { 246 return (errno); 247 } 248 /* 249 * the command was accepted so it exists. Await the reply (It's 250 * almost certainly already waiting). 251 */ 252 if (NgRecvMsg(*cfd, resp, sizeof(rbuf), NULL) < 0) { 253 return (errno); 254 } 255 /** 256 * The following is available about the node: 257 * ninfo->name (string) 258 * ninfo->type (string) 259 * ninfo->id (u_int32_t) 260 * ninfo->hooks (u_int32_t) (count of hooks) 261 * check it is the correct type. and get its ID for use 262 * with mkpeer later. 263 */ 264 if (strncmp(ninfo->type, NG_ETHER_NODE_TYPE, 265 strlen(NG_ETHER_NODE_TYPE)) != 0) { 266 return (EPROTOTYPE); 267 } 268 sprintf(source_ID, "[%08x]:", ninfo->id); 269 270 /* 271 * look for a hook already attached. 272 */ 273 for (k = 0; k < ninfo->hooks; k++) { 274 /** 275 * The following are available about each hook. 276 * link->ourhook (string) 277 * link->peerhook (string) 278 * peer->name (string) 279 * peer->type (string) 280 * peer->id (u_int32_t) 281 * peer->hooks (u_int32_t) 282 */ 283 link = &hlist->link[k]; 284 peer = &hlist->link[k].nodeinfo; 285 286 /* Ignore debug hooks */ 287 if (strcmp("debug", link->ourhook) == 0) 288 continue; 289 290 /* If the orphans hook is attached, use that */ 291 if (strcmp(NG_ETHER_HOOK_ORPHAN, 292 link->ourhook) == 0) { 293 break; 294 } 295 /* the other option is the 'divert' hook */ 296 if (strcmp("NG_ETHER_HOOK_DIVERT", 297 link->ourhook) == 0) { 298 break; 299 } 300 } 301 302 /* 303 * See if we found a hook there. 304 */ 305 if (k < ninfo->hooks) { 306 if (strcmp(peer->type, NG_PPPOE_NODE_TYPE) == 0) { 307 /* 308 * If it's a type pppoe, we skip making one 309 * ourself, but we continue, using 310 * the existing one. 311 */ 312 sprintf(pppoe_node_name, "[%08x]:", peer->id); 313 } else { 314 /* 315 * There is already someone hogging the data, 316 * return an error. Some day we'll try 317 * daisy-chaining.. 318 */ 319 return (EBUSY); 320 } 321 } else { 322 323 /* 324 * Try make a node of type pppoe against node "ID" 325 * On hook NG_ETHER_HOOK_ORPHAN. 326 */ 327 snprintf(mkp.type, sizeof(mkp.type), 328 "%s", NG_PPPOE_NODE_TYPE); 329 snprintf(mkp.ourhook, sizeof(mkp.ourhook), 330 "%s", NG_ETHER_HOOK_ORPHAN); 331 snprintf(mkp.peerhook, sizeof(mkp.peerhook), 332 "%s", NG_PPPOE_HOOK_ETHERNET); 333 /* Send message */ 334 if (NgSendMsg(*cfd, source_ID, NGM_GENERIC_COOKIE, 335 NGM_MKPEER, &mkp, sizeof(mkp)) < 0) { 336 return (errno); 337 } 338 /* 339 * Work out a name for the new node. 340 */ 341 sprintf(pppoe_node_name, "%s:%s", 342 source_ID, NG_ETHER_HOOK_ORPHAN); 343 } 344 /* 345 * We now have a pppoe node attached to the ethernet 346 * card. The Ethernet is addressed as ethername: The pppoe 347 * node is addressed as pppoe_node_name: attach to it. 348 * Connect socket node to specified node Use the same hook 349 * name on both ends of the link. 350 */ 351 snprintf(ngc.path, sizeof(ngc.path), "%s", pppoe_node_name); 352 snprintf(ngc.ourhook, sizeof(ngc.ourhook), "%s", sessname); 353 snprintf(ngc.peerhook, sizeof(ngc.peerhook), "%s", sessname); 354 355 if (NgSendMsg(*cfd, ".:", NGM_GENERIC_COOKIE, 356 NGM_CONNECT, &ngc, sizeof(ngc)) < 0) { 357 return (errno); 358 } 359 /* 360 * Send it a message telling it to start up. 361 */ 362 bzero(&message, sizeof(message)); 363 snprintf(message.idata.hook, sizeof(message.idata.hook), 364 "%s", sessname); 365 if (service == NULL) { 366 message.idata.data_len = 0; 367 } else { 368 snprintf(message.idata.data, 369 sizeof(message.idata.data), "%s", service); 370 message.idata.data_len = strlen(service); 371 } 372 /* Tell session/hook to start up as a client */ 373 if (NgSendMsg(*cfd, ngc.path, 374 NGM_PPPOE_COOKIE, NGM_PPPOE_CONNECT, &message.idata, 375 sizeof(message.idata) + message.idata.data_len) < 0) { 376 return (errno); 377 } 378 return (0); 379} 380.Ed 381.Sh SEE ALSO 382.Xr netgraph 3 , 383.Xr netgraph 4 , 384.Xr ng_ppp 4 , 385.Xr ng_socket 4 , 386.Xr ngctl 8 387.Rs 388.%A L. Mamakos 389.%A K. Lidl 390.%A J. Evarts 391.%A D. Carrel 392.%A D. Simone 393.%A R. Wheeler 394.%T "A Method for transmitting PPP over Ethernet (PPPoE)" 395.%O RFC 2516 396.Re 397.Sh HISTORY 398The 399.Nm 400node type was implemented in 401.Fx 4.0 . 402.Sh AUTHORS 403.An Julian Elischer Aq Mt julian@FreeBSD.org 404