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@whistle.com> 34.\" 35.\" $FreeBSD$ 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 8 40.Os FreeBSD 4.0 41.Sh NAME 42.Nm ng_pppoe 43.Nd RFC-2516 PPPOE protocol netgraph node type 44.Sh SYNOPSIS 45.Fd #include <netgraph/ng_pppoe.h> 46.Sh DESCRIPTION 47The 48.Nm 49node type performs the PPPoE protocol. It is used in conjunction with a the 50.Dv Netgraph 51extensions to the ethernet framework to divert and inject ethernet packets 52to and from a PPP agent (which is not specified). 53.Pp 54The 55.Dv NGM_PPPOE_GET_STATUS 56control message can be used at any time to query the current status 57of the PPPOE module. The only statistics presently available are the 58total packet counts for input and output. This node does not yet support 59the 60.Dv NGM_TEXT_STATUS 61control message. 62.Sh HOOKS 63This node type supports the following hooks: 64.Pp 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 it's 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 it's 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 it's 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 125.Pp 126The three commands above use a common data structure. 127.Dv "struct ngpppoe_init_data" 128.Bd -literal -offset 4n 129struct ngpppoe_init_data { 130 char hook[NG_HOOKLEN + 1]; /* hook to monitor on */ 131 u_int16_t data_len; /* Length of the service name */ 132 char data[0]; /* init data goes here */ 133}; 134.Ed 135 136.It Dv NGM_PPPOE_SUCCESS 137This command is sent to the node that started this session with one of the 138above messages, and reports a state change. This message reports 139successful Session negotiation. It uses the structure shown below, and 140reports back the hook name corresponding to the successful session. 141.It Dv NGM_NGM_PPPOE_FAIL 142This command is sent to the node that started this session with one of the 143above messages, and reports a state change. This message reports 144failed Session negotiation. It uses the structure shown below, and 145reports back the hook name corresponding to the failed session. 146The hook will probably have been removed immediately after sending this message 147.It Dv NGM_NGM_PPPOE_CLOSE 148This command is sent to the node that started this session with one of the 149above messages, and reports a state change. This message reports 150a request to close a session. It uses the structure shown below, and 151reports back the hook name corresponding to the closed session. 152The hook will probably have been removed immediately after sending this 153message. At present this message is not yet used and a 'failed' message 154will be received at closure instead. 155.Pp 156The three commands above use a common data structure. 157.Dv "struct ngpppoe_sts" 158.Bd -literal -offset 4n 159struct ngpppoe_sts { 160 char hook[NG_HOOKLEN + 1]; /* hook associated with event session */ 161}; 162 163.El 164.Sh SHUTDOWN 165This node shuts down upon receipt of a 166.Dv NGM_SHUTDOWN 167control message, when all session have been disconnected or when the 168.Dv ethernet 169hook is disconnected. 170.Sh EXAMPLE USAGE 171The following code uses 172.Dv libnetgraph 173to set up a 174.Nm 175node and connect it to both a socket node and an ethernet node. It can handle 176the case of when a 177.Nm 178node is already attached to the ethernet. It then starts a client session. 179.Bd -literal 180#include <stdio.h> 181#include <stdlib.h> 182#include <string.h> 183#include <ctype.h> 184#include <unistd.h> 185#include <sysexits.h> 186#include <errno.h> 187#include <err.h> 188 189#include <sys/types.h> 190#include <sys/socket.h> 191#include <sys/select.h> 192#include <net/ethernet.h> 193 194#include <netgraph.h> 195#include <netgraph/ng_ether.h> 196#include <netgraph/ng_pppoe.h> 197#include <netgraph/ng_socket.h> 198static int setup(char *ethername, char *service, char *sessname, 199 int *dfd, int *cfd); 200 201int 202main() 203{ 204 int fd1, fd2; 205 setup("xl0", NULL, "fred", &fd1, &fd2); 206 sleep (30); 207} 208 209static int 210setup(char *ethername, char *service, char *sessname, 211 int *dfd, int *cfd) 212{ 213 struct ngm_connect ngc; /* connect */ 214 struct ngm_mkpeer mkp; /* mkpeer */ 215 /******** nodeinfo stuff **********/ 216 u_char rbuf[2 * 1024]; 217 struct ng_mesg *const resp = (struct ng_mesg *) rbuf; 218 struct hooklist *const hlist 219 = (struct hooklist *) resp->data; 220 struct nodeinfo *const ninfo = &hlist->nodeinfo; 221 int ch, no_hooks = 0; 222 struct linkinfo *link; 223 struct nodeinfo *peer; 224 /****message to connect pppoe session*****/ 225 struct { 226 struct ngPPPoE_init_data idata; 227 char service[100]; 228 } message; 229 /********tracking our little graph ********/ 230 char path[100]; 231 char source_ID[NG_NODELEN + 1]; 232 char pppoe_node_name[100]; 233 int k; 234 235 /* 236 * Create the data and control sockets 237 */ 238 if (NgMkSockNode(NULL, cfd, dfd) < 0) { 239 return (errno); 240 } 241 /* 242 * find the ether node of the name requested by asking it for 243 * it's inquiry information. 244 */ 245 if (strlen(ethername) > 16) 246 return (EINVAL); 247 sprintf(path, "%s:", ethername); 248 if (NgSendMsg(*cfd, path, NGM_GENERIC_COOKIE, 249 NGM_LISTHOOKS, NULL, 0) < 0) { 250 return (errno); 251 } 252 /* 253 * the command was accepted so it exists. Await the reply (It's 254 * almost certainly already waiting). 255 */ 256 if (NgRecvMsg(*cfd, resp, sizeof(rbuf), NULL) < 0) { 257 return (errno); 258 } 259 /** 260 * The following is available about the node: 261 * ninfo->name (string) 262 * ninfo->type (string) 263 * ninfo->id (u_int32_t) 264 * ninfo->hooks (u_int32_t) (count of hooks) 265 * check it is the correct type. and get it's ID for use 266 * with mkpeer later. 267 */ 268 if (strncmp(ninfo->type, NG_ETHER_NODE_TYPE, 269 strlen(NG_ETHER_NODE_TYPE)) != 0) { 270 return (EPROTOTYPE); 271 } 272 sprintf(source_ID, "[%08x]:", ninfo->id); 273 274 /* 275 * look for a hook already attached. 276 */ 277 for (k = 0; k < ninfo->hooks; k++) { 278 /** 279 * The following are available about each hook. 280 * link->ourhook (string) 281 * link->peerhook (string) 282 * peer->name (string) 283 * peer->type (string) 284 * peer->id (u_int32_t) 285 * peer->hooks (u_int32_t) 286 */ 287 link = &hlist->link[k]; 288 peer = &hlist->link[k].nodeinfo; 289 290 /* Ignore debug hooks */ 291 if (strcmp("debug", link->ourhook) == 0) 292 continue; 293 294 /* If the orphans hook is attached, use that */ 295 if (strcmp(NG_ETHER_HOOK_ORPHAN, 296 link->ourhook) == 0) { 297 break; 298 } 299 /* the other option is the 'divert' hook */ 300 if (strcmp("NG_ETHER_HOOK_DIVERT", 301 link->ourhook) == 0) { 302 break; 303 } 304 } 305 306 /* 307 * See if we found a hook there. 308 */ 309 if (k < ninfo->hooks) { 310 if (strcmp(peer->type, NG_PPPOE_NODE_TYPE) == 0) { 311 /* 312 * If it's a type pppoe, we skip making one 313 * ourself, but we continue, using 314 * the existing one. 315 */ 316 sprintf(pppoe_node_name, "[%08x]:", peer->id); 317 } else { 318 /* 319 * There is already someone hogging the data, 320 * return an error. Some day we'll try 321 * daisy-chaining.. 322 */ 323 return (EBUSY); 324 } 325 } else { 326 327 /* 328 * Try make a node of type pppoe against node "ID" 329 * On hook NG_ETHER_HOOK_ORPHAN. 330 */ 331 snprintf(mkp.type, sizeof(mkp.type), 332 "%s", NG_PPPOE_NODE_TYPE); 333 snprintf(mkp.ourhook, sizeof(mkp.ourhook), 334 "%s", NG_ETHER_HOOK_ORPHAN); 335 snprintf(mkp.peerhook, sizeof(mkp.peerhook), 336 "%s", NG_PPPOE_HOOK_ETHERNET); 337 /* Send message */ 338 if (NgSendMsg(*cfd, source_ID, NGM_GENERIC_COOKIE, 339 NGM_MKPEER, &mkp, sizeof(mkp)) < 0) { 340 return (errno); 341 } 342 /* 343 * Work out a name for the new node. 344 */ 345 sprintf(pppoe_node_name, "%s:%s", 346 source_ID, NG_ETHER_HOOK_ORPHAN); 347 } 348 /* 349 * We now have a pppoe node attached to the ethernet 350 * card. The Ethernet is addressed as ethername: The pppoe 351 * node is addressed as pppoe_node_name: attach to it. 352 * Connect socket node to specified node Use the same hook 353 * name on both ends of the link. 354 */ 355 snprintf(ngc.path, sizeof(ngc.path), "%s", pppoe_node_name); 356 snprintf(ngc.ourhook, sizeof(ngc.ourhook), "%s", sessname); 357 snprintf(ngc.peerhook, sizeof(ngc.peerhook), "%s", sessname); 358 359 if (NgSendMsg(*cfd, ".:", NGM_GENERIC_COOKIE, 360 NGM_CONNECT, &ngc, sizeof(ngc)) < 0) { 361 return (errno); 362 } 363 /* 364 * Send it a message telling it to start up. 365 */ 366 bzero(&message, sizeof(message)); 367 snprintf(message.idata.hook, sizeof(message.idata.hook), 368 "%s", sessname); 369 if (service == NULL) { 370 message.idata.data_len = 0; 371 } else { 372 snprintf(message.idata.data, 373 sizeof(message.idata.data), "%s", service); 374 message.idata.data_len = strlen(service); 375 } 376 /* Tell session/hook to start up as a client */ 377 if (NgSendMsg(*cfd, ngc.path, 378 NGM_PPPOE_COOKIE, NGM_PPPOE_CONNECT, &message.idata, 379 sizeof(message.idata) + message.idata.data_len) < 0) { 380 return (errno); 381 } 382 return (0); 383} 384.Ed 385.Sh SEE ALSO 386.Xr netgraph 3 , 387.Xr netgraph 4 , 388.Xr ng_socket 8 , 389.Xr ngctl 8 . 390.Rs 391.%T "RFC 2516 - A Method of transmitting PPP over Ethernet (PPPoE)" 392.Re 393.Sh AUTHOR 394Julian Elischer <julian@whistle.com> 395