xref: /freebsd/sys/netgraph/ng_pppoe.c (revision ce46e2059e16557a44be599f86de42c0e1a13220)
1 
2 /*
3  * ng_pppoe.c
4  *
5  * Copyright (c) 1996-1999 Whistle Communications, Inc.
6  * All rights reserved.
7  *
8  * Subject to the following obligations and disclaimer of warranty, use and
9  * redistribution of this software, in source or object code forms, with or
10  * without modifications are expressly permitted by Whistle Communications;
11  * provided, however, that:
12  * 1. Any and all reproductions of the source or object code must include the
13  *    copyright notice above and the following disclaimer of warranties; and
14  * 2. No rights are granted, in any manner or form, to use Whistle
15  *    Communications, Inc. trademarks, including the mark "WHISTLE
16  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17  *    such appears in the above copyright notice or in the software.
18  *
19  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
25  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35  * OF SUCH DAMAGE.
36  *
37  * Author: Julian Elischer <julian@freebsd.org>
38  *
39  * $FreeBSD$
40  * $Whistle: ng_pppoe.c,v 1.10 1999/11/01 09:24:52 julian Exp $
41  */
42 #if 0
43 #define AAA printf("pppoe: %s\n", __func__ );
44 #define BBB printf("-%d-", __LINE__ );
45 #else
46 #define AAA
47 #define BBB
48 #endif
49 
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/kernel.h>
53 #include <sys/mbuf.h>
54 #include <sys/malloc.h>
55 #include <sys/errno.h>
56 #include <sys/sysctl.h>
57 #include <sys/syslog.h>
58 #include <net/ethernet.h>
59 
60 #include <netgraph/ng_message.h>
61 #include <netgraph/netgraph.h>
62 #include <netgraph/ng_parse.h>
63 #include <netgraph/ng_pppoe.h>
64 
65 #ifdef NG_SEPARATE_MALLOC
66 MALLOC_DEFINE(M_NETGRAPH_PPPOE, "netgraph_pppoe", "netgraph pppoe node");
67 #else
68 #define M_NETGRAPH_PPPOE M_NETGRAPH
69 #endif
70 
71 #define SIGNOFF "session closed"
72 #define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0))
73 
74 /*
75  * This section contains the netgraph method declarations for the
76  * pppoe node. These methods define the netgraph pppoe 'type'.
77  */
78 
79 static ng_constructor_t	ng_pppoe_constructor;
80 static ng_rcvmsg_t	ng_pppoe_rcvmsg;
81 static ng_shutdown_t	ng_pppoe_shutdown;
82 static ng_newhook_t	ng_pppoe_newhook;
83 static ng_connect_t	ng_pppoe_connect;
84 static ng_rcvdata_t	ng_pppoe_rcvdata;
85 static ng_disconnect_t	ng_pppoe_disconnect;
86 
87 /* Parse type for struct ngpppoe_init_data */
88 static const struct ng_parse_struct_field ngpppoe_init_data_type_fields[]
89 	= NG_PPPOE_INIT_DATA_TYPE_INFO;
90 static const struct ng_parse_type ngpppoe_init_data_state_type = {
91 	&ng_parse_struct_type,
92 	&ngpppoe_init_data_type_fields
93 };
94 
95 /* Parse type for struct ngpppoe_sts */
96 static const struct ng_parse_struct_field ng_pppoe_sts_type_fields[]
97 	= NG_PPPOE_STS_TYPE_INFO;
98 static const struct ng_parse_type ng_pppoe_sts_state_type = {
99 	&ng_parse_struct_type,
100 	&ng_pppoe_sts_type_fields
101 };
102 
103 /* List of commands and how to convert arguments to/from ASCII */
104 static const struct ng_cmdlist ng_pppoe_cmds[] = {
105 	{
106 	  NGM_PPPOE_COOKIE,
107 	  NGM_PPPOE_CONNECT,
108 	  "pppoe_connect",
109 	  &ngpppoe_init_data_state_type,
110 	  NULL
111 	},
112 	{
113 	  NGM_PPPOE_COOKIE,
114 	  NGM_PPPOE_LISTEN,
115 	  "pppoe_listen",
116 	  &ngpppoe_init_data_state_type,
117 	  NULL
118 	},
119 	{
120 	  NGM_PPPOE_COOKIE,
121 	  NGM_PPPOE_OFFER,
122 	  "pppoe_offer",
123 	  &ngpppoe_init_data_state_type,
124 	  NULL
125 	},
126 	{
127 	  NGM_PPPOE_COOKIE,
128 	  NGM_PPPOE_SERVICE,
129 	  "pppoe_service",
130 	  &ngpppoe_init_data_state_type,
131 	  NULL
132 	},
133 	{
134 	  NGM_PPPOE_COOKIE,
135 	  NGM_PPPOE_SUCCESS,
136 	  "pppoe_success",
137 	  &ng_pppoe_sts_state_type,
138 	  NULL
139 	},
140 	{
141 	  NGM_PPPOE_COOKIE,
142 	  NGM_PPPOE_FAIL,
143 	  "pppoe_fail",
144 	  &ng_pppoe_sts_state_type,
145 	  NULL
146 	},
147 	{
148 	  NGM_PPPOE_COOKIE,
149 	  NGM_PPPOE_CLOSE,
150 	  "pppoe_close",
151 	  &ng_pppoe_sts_state_type,
152 	  NULL
153 	},
154 	{
155 	  NGM_PPPOE_COOKIE,
156 	  NGM_PPPOE_SETMODE,
157 	  "pppoe_setmode",
158 	  &ng_parse_string_type,
159 	  NULL
160 	},
161 	{
162 	  NGM_PPPOE_COOKIE,
163 	  NGM_PPPOE_GETMODE,
164 	  "pppoe_getmode",
165 	  NULL,
166 	  &ng_parse_string_type
167 	},
168 	{ 0 }
169 };
170 
171 /* Netgraph node type descriptor */
172 static struct ng_type typestruct = {
173 	.version =	NG_ABI_VERSION,
174 	.name =		NG_PPPOE_NODE_TYPE,
175 	.constructor =	ng_pppoe_constructor,
176 	.rcvmsg =	ng_pppoe_rcvmsg,
177 	.shutdown =	ng_pppoe_shutdown,
178 	.newhook =	ng_pppoe_newhook,
179 	.connect =	ng_pppoe_connect,
180 	.rcvdata =	ng_pppoe_rcvdata,
181 	.disconnect =	ng_pppoe_disconnect,
182 	.cmdlist =	ng_pppoe_cmds,
183 };
184 NETGRAPH_INIT(pppoe, &typestruct);
185 /* Depend on ng_ether so we can use the Ethernet parse type */
186 MODULE_DEPEND(ng_pppoe, ng_ether, 1, 1, 1);
187 
188 /*
189  * States for the session state machine.
190  * These have no meaning if there is no hook attached yet.
191  */
192 enum state {
193     PPPOE_SNONE=0,	/* [both] Initial state */
194     PPPOE_LISTENING,	/* [Daemon] Listening for discover initiation pkt */
195     PPPOE_SINIT,	/* [Client] Sent discovery initiation */
196     PPPOE_PRIMED,	/* [Server] Awaiting PADI from daemon */
197     PPPOE_SOFFER,	/* [Server] Sent offer message  (got PADI)*/
198     PPPOE_SREQ,		/* [Client] Sent a Request */
199     PPPOE_NEWCONNECTED,	/* [Server] Connection established, No data received */
200     PPPOE_CONNECTED,	/* [Both] Connection established, Data received */
201     PPPOE_DEAD		/* [Both] */
202 };
203 
204 #define NUMTAGS 20 /* number of tags we are set up to work with */
205 
206 /*
207  * Information we store for each hook on each node for negotiating the
208  * session. The mbuf and cluster are freed once negotiation has completed.
209  * The whole negotiation block is then discarded.
210  */
211 
212 struct sess_neg {
213 	struct mbuf 		*m; /* holds cluster with last sent packet */
214 	union	packet		*pkt; /* points within the above cluster */
215 	struct callout_handle	timeout_handle;   /* see timeout(9) */
216 	u_int			timeout; /* 0,1,2,4,8,16 etc. seconds */
217 	u_int			numtags;
218 	const struct pppoe_tag	*tags[NUMTAGS];
219 	u_int			service_len;
220 	u_int			ac_name_len;
221 
222 	struct datatag		service;
223 	struct datatag		ac_name;
224 };
225 typedef struct sess_neg *negp;
226 
227 /*
228  * Session information that is needed after connection.
229  */
230 struct sess_con {
231 	hook_p  		hook;
232 	u_int16_t		Session_ID;
233 	enum state		state;
234 	ng_ID_t			creator;		/* who to notify */
235 	struct pppoe_full_hdr	pkt_hdr;	/* used when connected */
236 	negp			neg;		/* used when negotiating */
237 	/*struct sess_con	*hash_next;*/	/* not yet used */
238 };
239 typedef struct sess_con *sessp;
240 
241 #define	NG_PPPOE_SESSION_NODE(sp) NG_HOOK_NODE(sp->hook)
242 
243 enum {
244 	PPPOE_STANDARD	= 1,	/* standard RFC2516 mode */
245 	PPPOE_NONSTANDARD,	/* 3Com proprietary mode */
246 };
247 
248 struct ng_pppoe_mode_t {
249 	u_int8_t        		id;
250 	const struct ether_header	*eh_prototype;
251 	const char      		*name;
252 };
253 
254 static const struct ether_header eh_standard =
255 	{{0xff,0xff,0xff,0xff,0xff,0xff},
256 	{0x00,0x00,0x00,0x00,0x00,0x00},
257 	ETHERTYPE_PPPOE_DISC};
258 
259 static const struct ether_header eh_3Com =
260 	{{0xff,0xff,0xff,0xff,0xff,0xff},
261 	{0x00,0x00,0x00,0x00,0x00,0x00},
262 	ETHERTYPE_PPPOE_STUPID_DISC};
263 
264 static const struct ng_pppoe_mode_t ng_pppoe_modes[] = {
265 	{ PPPOE_STANDARD,	&eh_standard,	NG_PPPOE_STANDARD },
266 	{ PPPOE_NONSTANDARD,	&eh_3Com,	NG_PPPOE_NONSTANDARD },
267 	{ 0, NULL},
268 };
269 
270 /*
271  * Information we store for each node
272  */
273 struct PPPOE {
274 	node_p		node;		/* back pointer to node */
275 	hook_p  	ethernet_hook;
276 	hook_p  	debug_hook;
277 	u_int   	packets_in;	/* packets in from ethernet */
278 	u_int   	packets_out;	/* packets out towards ethernet */
279 	u_int32_t	flags;
280 	const struct ng_pppoe_mode_t	*mode;	/* standard PPPoE or 3Com? */
281 	/*struct sess_con *buckets[HASH_SIZE];*/	/* not yet used */
282 };
283 typedef struct PPPOE *priv_p;
284 
285 /* Deprecated sysctl, leaved here to keep compatibility for some time */
286 #define PPPOE_SYSCTL_KEEPSTANDARD	-1
287 #define PPPOE_SYSCTL_STANDARD		0
288 #define PPPOE_SYSCTL_NONSTANDARD	1
289 static int pppoe_mode = PPPOE_SYSCTL_KEEPSTANDARD;
290 static const struct ng_pppoe_mode_t *sysctl_mode = ng_pppoe_modes;
291 
292 static int
293 ngpppoe_set_ethertype(SYSCTL_HANDLER_ARGS)
294 {
295 	int error;
296 	int val;
297 
298 	val = pppoe_mode;
299 	error = sysctl_handle_int(oidp, &val, sizeof(int), req);
300 	if (error != 0 || req->newptr == NULL)
301 		return (error);
302 	switch (val) {
303 	case PPPOE_SYSCTL_NONSTANDARD:
304 		sysctl_mode = ng_pppoe_modes + 1;
305 		break;
306 	case PPPOE_SYSCTL_STANDARD:
307 	case PPPOE_SYSCTL_KEEPSTANDARD:
308 		sysctl_mode = ng_pppoe_modes;
309 		break;
310 	default:
311 		return (EINVAL);
312 	}
313 
314 	pppoe_mode = val;
315 	printf("net.graph.nonstandard_pppoe is deprecated. See ng_pppoe(4), ppp(8).\n");
316 	return (0);
317 }
318 
319 SYSCTL_PROC(_net_graph, OID_AUTO, nonstandard_pppoe, CTLTYPE_INT | CTLFLAG_RW,
320     0, sizeof(int), ngpppoe_set_ethertype, "I", "select normal or stupid ISP");
321 
322 union uniq {
323 	char bytes[sizeof(void *)];
324 	void * pointer;
325 	};
326 
327 #define	LEAVE(x) do { error = x; goto quit; } while(0)
328 static void	pppoe_start(sessp sp);
329 static void	sendpacket(sessp sp);
330 static void	pppoe_ticker(void *arg);
331 static const	struct pppoe_tag *scan_tags(sessp sp,
332 			const struct pppoe_hdr* ph);
333 static	int	pppoe_send_event(sessp sp, enum cmd cmdid);
334 
335 /*************************************************************************
336  * Some basic utilities  from the Linux version with author's permission.*
337  * Author:	Michal Ostrowski <mostrows@styx.uwaterloo.ca>		 *
338  ************************************************************************/
339 
340 /*
341  * Generate a new session id
342  * XXX find out the FreeBSD locking scheme.
343  */
344 static u_int16_t
345 get_new_sid(node_p node)
346 {
347 	static int pppoe_sid = 10;
348 	sessp sp;
349 	hook_p	hook;
350 	u_int16_t val;
351 	priv_p privp = NG_NODE_PRIVATE(node);
352 
353 AAA
354 restart:
355 	val = pppoe_sid++;
356 	/*
357 	 * Spec says 0xFFFF is reserved.
358 	 * Also don't use 0x0000
359 	 */
360 	if (val == 0xffff) {
361 		pppoe_sid = 20;
362 		goto restart;
363 	}
364 
365 	/* Check it isn't already in use */
366 	LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) {
367 		/* don't check special hooks */
368 		if ((NG_HOOK_PRIVATE(hook) == &privp->debug_hook)
369 		||  (NG_HOOK_PRIVATE(hook) == &privp->ethernet_hook))
370 			continue;
371 		sp = NG_HOOK_PRIVATE(hook);
372 		if (sp->Session_ID == val)
373 			goto restart;
374 	}
375 
376 	return val;
377 }
378 
379 
380 /*
381  * Return the location where the next tag can be put
382  */
383 static __inline const struct pppoe_tag*
384 next_tag(const struct pppoe_hdr* ph)
385 {
386 	return (const struct pppoe_tag*)(((const char*)&ph->tag[0])
387 	    + ntohs(ph->length));
388 }
389 
390 /*
391  * Look for a tag of a specific type
392  * Don't trust any length the other end says.
393  * but assume we already sanity checked ph->length.
394  */
395 static const struct pppoe_tag*
396 get_tag(const struct pppoe_hdr* ph, u_int16_t idx)
397 {
398 	const char *const end = (const char *)next_tag(ph);
399 	const char *ptn;
400 	const struct pppoe_tag *pt = &ph->tag[0];
401 	/*
402 	 * Keep processing tags while a tag header will still fit.
403 	 */
404 AAA
405 	while((const char*)(pt + 1) <= end) {
406 	    /*
407 	     * If the tag data would go past the end of the packet, abort.
408 	     */
409 	    ptn = (((const char *)(pt + 1)) + ntohs(pt->tag_len));
410 	    if(ptn > end)
411 		return NULL;
412 
413 	    if(pt->tag_type == idx)
414 		return pt;
415 
416 	    pt = (const struct pppoe_tag*)ptn;
417 	}
418 	return NULL;
419 }
420 
421 /**************************************************************************
422  * inlines to initialise or add tags to a session's tag list,
423  **************************************************************************/
424 /*
425  * Initialise the session's tag list
426  */
427 static void
428 init_tags(sessp sp)
429 {
430 AAA
431 	if(sp->neg == NULL) {
432 		printf("pppoe: asked to init NULL neg pointer\n");
433 		return;
434 	}
435 	sp->neg->numtags = 0;
436 }
437 
438 static void
439 insert_tag(sessp sp, const struct pppoe_tag *tp)
440 {
441 	int	i;
442 	negp neg;
443 
444 AAA
445 	if((neg = sp->neg) == NULL) {
446 		printf("pppoe: asked to use NULL neg pointer\n");
447 		return;
448 	}
449 	if ((i = neg->numtags++) < NUMTAGS) {
450 		neg->tags[i] = tp;
451 	} else {
452 		printf("pppoe: asked to add too many tags to packet\n");
453 		neg->numtags--;
454 	}
455 }
456 
457 /*
458  * Make up a packet, using the tags filled out for the session.
459  *
460  * Assume that the actual pppoe header and ethernet header
461  * are filled out externally to this routine.
462  * Also assume that neg->wh points to the correct
463  * location at the front of the buffer space.
464  */
465 static void
466 make_packet(sessp sp) {
467 	struct pppoe_full_hdr *wh = &sp->neg->pkt->pkt_header;
468 	const struct pppoe_tag **tag;
469 	char *dp;
470 	int count;
471 	int tlen;
472 	u_int16_t length = 0;
473 
474 AAA
475 	if ((sp->neg == NULL) || (sp->neg->m == NULL)) {
476 		printf("pppoe: make_packet called from wrong state\n");
477 	}
478 	dp = (char *)wh->ph.tag;
479 	for (count = 0, tag = sp->neg->tags;
480 	    ((count < sp->neg->numtags) && (count < NUMTAGS));
481 	    tag++, count++) {
482 		tlen = ntohs((*tag)->tag_len) + sizeof(**tag);
483 		if ((length + tlen) > (ETHER_MAX_LEN - 4 - sizeof(*wh))) {
484 			printf("pppoe: tags too long\n");
485 			sp->neg->numtags = count;
486 			break;	/* XXX chop off what's too long */
487 		}
488 		bcopy(*tag, (char *)dp, tlen);
489 		length += tlen;
490 		dp += tlen;
491 	}
492  	wh->ph.length = htons(length);
493 	sp->neg->m->m_len = length + sizeof(*wh);
494 	sp->neg->m->m_pkthdr.len = length + sizeof(*wh);
495 }
496 
497 /**************************************************************************
498  * Routine to match a service offered					  *
499  **************************************************************************/
500 /*
501  * Find a hook that has a service string that matches that
502  * we are seeking. for now use a simple string.
503  * In the future we may need something like regexp().
504  * for testing allow a null string to match 1st found and a null service
505  * to match all requests. Also make '*' do the same.
506  */
507 
508 #define NG_MATCH_EXACT	1
509 #define NG_MATCH_ANY	2
510 
511 static hook_p
512 pppoe_match_svc(node_p node, const char *svc_name, int svc_len, int match)
513 {
514 	sessp	sp	= NULL;
515 	negp	neg	= NULL;
516 	priv_p	privp	= NG_NODE_PRIVATE(node);
517 	hook_p	allhook	= NULL;
518 	hook_p	hook;
519 
520 AAA
521 	LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) {
522 
523 		/* skip any hook that is debug or ethernet */
524 		if ((NG_HOOK_PRIVATE(hook) == &privp->debug_hook)
525 		||  (NG_HOOK_PRIVATE(hook) == &privp->ethernet_hook))
526 			continue;
527 		sp = NG_HOOK_PRIVATE(hook);
528 
529 		/* Skip any sessions which are not in LISTEN mode. */
530 		if ( sp->state != PPPOE_LISTENING)
531 			continue;
532 
533 		neg = sp->neg;
534 
535 		/* Special case for a blank or "*" service name (wildcard) */
536 		if (match == NG_MATCH_ANY && neg->service_len == 1 &&
537 		    neg->service.data[0] == '*') {
538 			allhook = hook;
539 			continue;
540 		}
541 
542 		/* If the lengths don't match, that aint it. */
543 		if (neg->service_len != svc_len)
544 			continue;
545 
546 		/* An exact match? */
547 		if (svc_len == 0)
548 			break;
549 
550 		if (strncmp(svc_name, neg->service.data, svc_len) == 0)
551 			break;
552 	}
553 	return (hook ? hook : allhook);
554 }
555 /**************************************************************************
556  * Routine to find a particular session that matches an incoming packet	  *
557  **************************************************************************/
558 static hook_p
559 pppoe_findsession(node_p node, const struct pppoe_full_hdr *wh)
560 {
561 	sessp	sp = NULL;
562 	hook_p hook = NULL;
563 	priv_p	privp = NG_NODE_PRIVATE(node);
564 	u_int16_t	session = ntohs(wh->ph.sid);
565 
566 	/*
567 	 * find matching peer/session combination.
568 	 */
569 AAA
570 	LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) {
571 		/* don't check special hooks */
572 		if ((NG_HOOK_PRIVATE(hook) == &privp->debug_hook)
573 		||  (NG_HOOK_PRIVATE(hook) == &privp->ethernet_hook)) {
574 			continue;
575 		}
576 		sp = NG_HOOK_PRIVATE(hook);
577 		if ( ( (sp->state == PPPOE_CONNECTED)
578 		    || (sp->state == PPPOE_NEWCONNECTED) )
579 		&& (sp->Session_ID == session)
580 		&& (bcmp(sp->pkt_hdr.eh.ether_dhost,
581 		    wh->eh.ether_shost,
582 		    ETHER_ADDR_LEN)) == 0) {
583 			break;
584 		}
585 	}
586 	return (hook);
587 }
588 
589 static hook_p
590 pppoe_finduniq(node_p node, const struct pppoe_tag *tag)
591 {
592 	hook_p hook = NULL;
593 	priv_p	privp = NG_NODE_PRIVATE(node);
594 	union uniq		uniq;
595 
596 AAA
597 	bcopy(tag->tag_data, uniq.bytes, sizeof(void *));
598 	/* cycle through all known hooks */
599 	LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) {
600 		/* don't check special hooks */
601 		if ((NG_HOOK_PRIVATE(hook) == &privp->debug_hook)
602 		||  (NG_HOOK_PRIVATE(hook) == &privp->ethernet_hook))
603 			continue;
604 		if (uniq.pointer == NG_HOOK_PRIVATE(hook))
605 			break;
606 	}
607 	return (hook);
608 }
609 
610 /**************************************************************************
611  * start of Netgraph entrypoints					  *
612  **************************************************************************/
613 
614 /*
615  * Allocate the private data structure and the generic node
616  * and link them together.
617  *
618  * ng_make_node_common() returns with a generic node struct
619  * with a single reference for us.. we transfer it to the
620  * private structure.. when we free the private struct we must
621  * unref the node so it gets freed too.
622  */
623 static int
624 ng_pppoe_constructor(node_p node)
625 {
626 	priv_p privdata;
627 
628 AAA
629 	/* Initialize private descriptor */
630 	MALLOC(privdata, priv_p, sizeof(*privdata), M_NETGRAPH_PPPOE,
631 	    M_NOWAIT | M_ZERO);
632 	if (privdata == NULL)
633 		return (ENOMEM);
634 
635 	/* Link structs together; this counts as our one reference to *nodep */
636 	NG_NODE_SET_PRIVATE(node, privdata);
637 	privdata->node = node;
638 
639 	/* Initialize to standard mode (the first one in ng_pppoe_modes[]). */
640 	privdata->mode = sysctl_mode;
641 
642 	return (0);
643 }
644 
645 /*
646  * Give our ok for a hook to be added...
647  * point the hook's private info to the hook structure.
648  *
649  * The following hook names are special:
650  *  Ethernet:  the hook that should be connected to a NIC.
651  *  debug:	copies of data sent out here  (when I write the code).
652  * All other hook names need only be unique. (the framework checks this).
653  */
654 static int
655 ng_pppoe_newhook(node_p node, hook_p hook, const char *name)
656 {
657 	const priv_p privp = NG_NODE_PRIVATE(node);
658 	sessp sp;
659 
660 AAA
661 	if (strcmp(name, NG_PPPOE_HOOK_ETHERNET) == 0) {
662 		privp->ethernet_hook = hook;
663 		NG_HOOK_SET_PRIVATE(hook, &privp->ethernet_hook);
664 	} else if (strcmp(name, NG_PPPOE_HOOK_DEBUG) == 0) {
665 		privp->debug_hook = hook;
666 		NG_HOOK_SET_PRIVATE(hook, &privp->debug_hook);
667 	} else {
668 		/*
669 		 * Any other unique name is OK.
670 		 * The infrastructure has already checked that it's unique,
671 		 * so just allocate it and hook it in.
672 		 */
673 		MALLOC(sp, sessp, sizeof(*sp), M_NETGRAPH_PPPOE, M_NOWAIT | M_ZERO);
674 		if (sp == NULL) {
675 				return (ENOMEM);
676 		}
677 
678 		NG_HOOK_SET_PRIVATE(hook, sp);
679 		sp->hook = hook;
680 	}
681 	return(0);
682 }
683 
684 /*
685  * Get a netgraph control message.
686  * Check it is one we understand. If needed, send a response.
687  * We sometimes save the address for an async action later.
688  * Always free the message.
689  */
690 static int
691 ng_pppoe_rcvmsg(node_p node, item_p item, hook_p lasthook)
692 {
693 	priv_p privp = NG_NODE_PRIVATE(node);
694 	struct ngpppoe_init_data *ourmsg = NULL;
695 	struct ng_mesg *resp = NULL;
696 	int error = 0;
697 	hook_p hook = NULL;
698 	sessp sp = NULL;
699 	negp neg = NULL;
700 	struct ng_mesg *msg;
701 
702 AAA
703 	NGI_GET_MSG(item, msg);
704 	/* Deal with message according to cookie and command */
705 	switch (msg->header.typecookie) {
706 	case NGM_PPPOE_COOKIE:
707 		switch (msg->header.cmd) {
708 		case NGM_PPPOE_CONNECT:
709 		case NGM_PPPOE_LISTEN:
710 		case NGM_PPPOE_OFFER:
711 		case NGM_PPPOE_SERVICE:
712 			ourmsg = (struct ngpppoe_init_data *)msg->data;
713 			if (msg->header.arglen < sizeof(*ourmsg)) {
714 				printf("pppoe: init data too small\n");
715 				LEAVE(EMSGSIZE);
716 			}
717 			if (msg->header.arglen - sizeof(*ourmsg) >
718 			    PPPOE_SERVICE_NAME_SIZE) {
719 				printf("pppoe_rcvmsg: service name too big");
720 				LEAVE(EMSGSIZE);
721 			}
722 			if (msg->header.arglen - sizeof(*ourmsg) <
723 			    ourmsg->data_len) {
724 				printf("pppoe: init data has bad length,"
725 				    " %d should be %zd\n", ourmsg->data_len,
726 				    msg->header.arglen - sizeof (*ourmsg));
727 				LEAVE(EMSGSIZE);
728 			}
729 
730 			/* make sure strcmp will terminate safely */
731 			ourmsg->hook[sizeof(ourmsg->hook) - 1] = '\0';
732 
733 			/* cycle through all known hooks */
734 			LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) {
735 				if (NG_HOOK_NAME(hook)
736 				&& strcmp(NG_HOOK_NAME(hook), ourmsg->hook) == 0)
737 					break;
738 			}
739 			if (hook == NULL) {
740 				LEAVE(ENOENT);
741 			}
742 			if ((NG_HOOK_PRIVATE(hook) == &privp->debug_hook)
743 			||  (NG_HOOK_PRIVATE(hook) == &privp->ethernet_hook)) {
744 				LEAVE(EINVAL);
745 			}
746 			sp = NG_HOOK_PRIVATE(hook);
747 
748 			if (msg->header.cmd == NGM_PPPOE_LISTEN) {
749 				/*
750 				 * Ensure we aren't already listening for this
751 				 * service.
752 				 */
753 				if (pppoe_match_svc(node, ourmsg->data,
754 				    ourmsg->data_len, NG_MATCH_EXACT) != NULL) {
755 					LEAVE(EEXIST);
756 				}
757 			}
758 
759 			/*
760 			 * PPPOE_SERVICE advertisments are set up
761 			 * on sessions that are in PRIMED state.
762 			 */
763 			if (msg->header.cmd == NGM_PPPOE_SERVICE) {
764 				break;
765 			}
766 			if (sp->state |= PPPOE_SNONE) {
767 				printf("pppoe: Session already active\n");
768 				LEAVE(EISCONN);
769 			}
770 
771 			/*
772 			 * set up prototype header
773 			 */
774 			MALLOC(neg, negp, sizeof(*neg), M_NETGRAPH_PPPOE,
775 			    M_NOWAIT | M_ZERO);
776 
777 			if (neg == NULL) {
778 				printf("pppoe: Session out of memory\n");
779 				LEAVE(ENOMEM);
780 			}
781 			MGETHDR(neg->m, M_DONTWAIT, MT_DATA);
782 			if(neg->m == NULL) {
783 				printf("pppoe: Session out of mbufs\n");
784 				FREE(neg, M_NETGRAPH_PPPOE);
785 				LEAVE(ENOBUFS);
786 			}
787 			neg->m->m_pkthdr.rcvif = NULL;
788 			MCLGET(neg->m, M_DONTWAIT);
789 			if ((neg->m->m_flags & M_EXT) == 0) {
790 				printf("pppoe: Session out of mcls\n");
791 				m_freem(neg->m);
792 				FREE(neg, M_NETGRAPH_PPPOE);
793 				LEAVE(ENOBUFS);
794 			}
795 			sp->neg = neg;
796 			callout_handle_init( &neg->timeout_handle);
797 			neg->m->m_len = sizeof(struct pppoe_full_hdr);
798 			neg->pkt = mtod(neg->m, union packet*);
799 			memcpy((void *)&neg->pkt->pkt_header.eh,
800 			    (const void *)privp->mode->eh_prototype,
801 			    sizeof(struct ether_header));
802 			neg->pkt->pkt_header.ph.ver = 0x1;
803 			neg->pkt->pkt_header.ph.type = 0x1;
804 			neg->pkt->pkt_header.ph.sid = 0x0000;
805 			neg->timeout = 0;
806 
807 			sp->creator = NGI_RETADDR(item);
808 		}
809 		switch (msg->header.cmd) {
810 		case NGM_PPPOE_GET_STATUS:
811 		    {
812 			struct ngpppoestat *stats;
813 
814 			NG_MKRESPONSE(resp, msg, sizeof(*stats), M_NOWAIT);
815 			if (!resp) {
816 				LEAVE(ENOMEM);
817 			}
818 			stats = (struct ngpppoestat *) resp->data;
819 			stats->packets_in = privp->packets_in;
820 			stats->packets_out = privp->packets_out;
821 			break;
822 		    }
823 		case NGM_PPPOE_CONNECT:
824 			/*
825 			 * Check the hook exists and is Uninitialised.
826 			 * Send a PADI request, and start the timeout logic.
827 			 * Store the originator of this message so we can send
828 			 * a success of fail message to them later.
829 			 * Move the session to SINIT
830 			 * Set up the session to the correct state and
831 			 * start it.
832 			 */
833 			neg->service.hdr.tag_type = PTT_SRV_NAME;
834 			neg->service.hdr.tag_len =
835 			    htons((u_int16_t)ourmsg->data_len);
836 			if (ourmsg->data_len)
837 				bcopy(ourmsg->data, neg->service.data,
838 				    ourmsg->data_len);
839 			neg->service_len = ourmsg->data_len;
840 			pppoe_start(sp);
841 			break;
842 		case NGM_PPPOE_LISTEN:
843 			/*
844 			 * Check the hook exists and is Uninitialised.
845 			 * Install the service matching string.
846 			 * Store the originator of this message so we can send
847 			 * a success of fail message to them later.
848 			 * Move the hook to 'LISTENING'
849 			 */
850 			neg->service.hdr.tag_type = PTT_SRV_NAME;
851 			neg->service.hdr.tag_len =
852 			    htons((u_int16_t)ourmsg->data_len);
853 
854 			if (ourmsg->data_len)
855 				bcopy(ourmsg->data, neg->service.data,
856 				    ourmsg->data_len);
857 			neg->service_len = ourmsg->data_len;
858 			neg->pkt->pkt_header.ph.code = PADT_CODE;
859 			/*
860 			 * wait for PADI packet coming from ethernet
861 			 */
862 			sp->state = PPPOE_LISTENING;
863 			break;
864 		case NGM_PPPOE_OFFER:
865 			/*
866 			 * Check the hook exists and is Uninitialised.
867 			 * Store the originator of this message so we can send
868 			 * a success of fail message to them later.
869 			 * Store the AC-Name given and go to PRIMED.
870 			 */
871 			neg->ac_name.hdr.tag_type = PTT_AC_NAME;
872 			neg->ac_name.hdr.tag_len =
873 			    htons((u_int16_t)ourmsg->data_len);
874 			if (ourmsg->data_len)
875 				bcopy(ourmsg->data, neg->ac_name.data,
876 				    ourmsg->data_len);
877 			neg->ac_name_len = ourmsg->data_len;
878 			neg->pkt->pkt_header.ph.code = PADO_CODE;
879 			/*
880 			 * Wait for PADI packet coming from hook
881 			 */
882 			sp->state = PPPOE_PRIMED;
883 			break;
884 		case NGM_PPPOE_SERVICE:
885 			/*
886 			 * Check the session is primed.
887 			 * for now just allow ONE service to be advertised.
888 			 * If you do it twice you just overwrite.
889 			 */
890 			if (sp->state != PPPOE_PRIMED) {
891 				printf("pppoe: Session not primed\n");
892 				LEAVE(EISCONN);
893 			}
894 			neg = sp->neg;
895 			neg->service.hdr.tag_type = PTT_SRV_NAME;
896 			neg->service.hdr.tag_len =
897 			    htons((u_int16_t)ourmsg->data_len);
898 
899 			if (ourmsg->data_len)
900 				bcopy(ourmsg->data, neg->service.data,
901 				    ourmsg->data_len);
902 			neg->service_len = ourmsg->data_len;
903 			break;
904 		case NGM_PPPOE_SETMODE:
905 		    {
906 			const struct ng_pppoe_mode_t *mode;
907 			char *s;
908 			size_t len;
909 
910 			if (msg->header.arglen == 0)
911 				LEAVE(EINVAL);
912 
913 			s = (char *)msg->data;
914 			len = msg->header.arglen - 1;
915 
916 			/* Search for matching mode string */
917 			for (mode = ng_pppoe_modes; mode->id != 0; mode++ )
918 				if ((strlen(mode->name) == len) &&
919 				    !strncmp(mode->name, s, len))
920 					break;	/* found */
921 
922 			if (mode->id != 0)
923 				privp->mode = mode;
924 			else
925 				LEAVE(EINVAL);
926 			break;
927 		    }
928 		case NGM_PPPOE_GETMODE:
929 			NG_MKRESPONSE(resp, msg, strlen(privp->mode->name) + 1,
930 			    M_NOWAIT);
931 			if (resp == NULL)
932 				LEAVE(ENOMEM);
933 			strlcpy((char *)resp->data, privp->mode->name,
934 			    strlen(privp->mode->name) + 1);
935 			break;
936 		default:
937 			LEAVE(EINVAL);
938 		}
939 		break;
940 	default:
941 		LEAVE(EINVAL);
942 	}
943 
944 	/* Take care of synchronous response, if any */
945 quit:
946 	NG_RESPOND_MSG(error, node, item, resp);
947 	/* Free the message and return */
948 	NG_FREE_MSG(msg);
949 	return(error);
950 }
951 
952 /*
953  * Start a client into the first state. A separate function because
954  * it can be needed if the negotiation times out.
955  */
956 static void
957 pppoe_start(sessp sp)
958 {
959 	priv_p	privp = NG_NODE_PRIVATE(NG_PPPOE_SESSION_NODE(sp));
960 	struct {
961 		struct pppoe_tag hdr;
962 		union	uniq	data;
963 	} __packed uniqtag;
964 
965 	/*
966 	 * kick the state machine into starting up
967 	 */
968 AAA
969 	sp->state = PPPOE_SINIT;
970 	/* Reset the packet header to broadcast. Since we are in a client
971 	 * mode use configured ethertype. */
972 	memcpy((void *)&sp->neg->pkt->pkt_header.eh,
973 	    (const void *)privp->mode->eh_prototype,
974 	    sizeof(struct ether_header));
975 	sp->neg->pkt->pkt_header.ph.code = PADI_CODE;
976 	uniqtag.hdr.tag_type = PTT_HOST_UNIQ;
977 	uniqtag.hdr.tag_len = htons((u_int16_t)sizeof(uniqtag.data));
978 	uniqtag.data.pointer = sp;
979 	init_tags(sp);
980 	insert_tag(sp, &uniqtag.hdr);
981 	insert_tag(sp, &sp->neg->service.hdr);
982 	make_packet(sp);
983 	sendpacket(sp);
984 }
985 
986 static int
987 send_acname(sessp sp, const struct pppoe_tag *tag)
988 {
989 	int error, tlen;
990 	struct ng_mesg *msg;
991 	struct ngpppoe_sts *sts;
992 
993 	NG_MKMESSAGE(msg, NGM_PPPOE_COOKIE, NGM_PPPOE_ACNAME,
994 	    sizeof(struct ngpppoe_sts), M_NOWAIT);
995 	if (msg == NULL)
996 		return (ENOMEM);
997 
998 	sts = (struct ngpppoe_sts *)msg->data;
999 	tlen = min(NG_HOOKSIZ - 1, ntohs(tag->tag_len));
1000 	strncpy(sts->hook, tag->tag_data, tlen);
1001 	sts->hook[tlen] = '\0';
1002 	NG_SEND_MSG_ID(error, NG_HOOK_NODE(sp->hook), msg, sp->creator, 0);
1003 
1004 	return (error);
1005 }
1006 
1007 static int
1008 send_sessionid(sessp sp)
1009 {
1010 	int error;
1011 	struct ng_mesg *msg;
1012 
1013 	NG_MKMESSAGE(msg, NGM_PPPOE_COOKIE, NGM_PPPOE_SESSIONID,
1014 	    sizeof(u_int16_t), M_NOWAIT);
1015 	if (msg == NULL)
1016 		return (ENOMEM);
1017 
1018 	*(u_int16_t *)msg->data = sp->Session_ID;
1019 	NG_SEND_MSG_ID(error, NG_HOOK_NODE(sp->hook), msg, sp->creator, 0);
1020 
1021 	return (error);
1022 }
1023 
1024 /*
1025  * Receive data, and do something with it.
1026  * The caller will never free m, so if we use up this data
1027  * or abort we must free it.
1028  */
1029 static int
1030 ng_pppoe_rcvdata(hook_p hook, item_p item)
1031 {
1032 	node_p			node = NG_HOOK_NODE(hook);
1033 	const priv_p		privp = NG_NODE_PRIVATE(node);
1034 	sessp			sp = NG_HOOK_PRIVATE(hook);
1035 	const struct pppoe_full_hdr *wh;
1036 	const struct pppoe_hdr	*ph;
1037 	int			error = 0;
1038 	u_int16_t		session;
1039 	u_int16_t		length;
1040 	u_int8_t		code;
1041 	const struct pppoe_tag	*utag = NULL, *tag = NULL;
1042 	hook_p 			sendhook;
1043 	struct {
1044 		struct pppoe_tag hdr;
1045 		union	uniq	data;
1046 	} __packed uniqtag;
1047 	negp			neg = NULL;
1048 	struct mbuf		*m;
1049 
1050 AAA
1051 	NGI_GET_M(item, m);
1052 	if (NG_HOOK_PRIVATE(hook) == &privp->debug_hook) {
1053 		/*
1054 		 * Data from the debug hook gets sent without modification
1055 		 * straight to the ethernet.
1056 		 */
1057 		NG_FWD_ITEM_HOOK( error, item, privp->ethernet_hook);
1058 	 	privp->packets_out++;
1059 	} else if (NG_HOOK_PRIVATE(hook) == &privp->ethernet_hook) {
1060 		/*
1061 		 * Incoming data.
1062 		 * Dig out various fields from the packet.
1063 		 * use them to decide where to send it.
1064 		 */
1065 
1066  		privp->packets_in++;
1067 		if( m->m_len < sizeof(*wh)) {
1068 			m = m_pullup(m, sizeof(*wh)); /* Checks length */
1069 			if (m == NULL) {
1070 				printf("couldn't m_pullup\n");
1071 				LEAVE(ENOBUFS);
1072 			}
1073 		}
1074 		wh = mtod(m, struct pppoe_full_hdr *);
1075 		length = ntohs(wh->ph.length);
1076 		switch(wh->eh.ether_type) {
1077 		case	ETHERTYPE_PPPOE_STUPID_DISC: /* fall through */
1078 		case	ETHERTYPE_PPPOE_DISC:
1079 			/*
1080 			 * We need to try to make sure that the tag area
1081 			 * is contiguous, or we could wander off the end
1082 			 * of a buffer and make a mess.
1083 			 * (Linux wouldn't have this problem).
1084 			 */
1085 			if (m->m_pkthdr.len <= MHLEN) {
1086 				if( m->m_len < m->m_pkthdr.len) {
1087 					m = m_pullup(m, m->m_pkthdr.len);
1088 					if (m == NULL) {
1089 						printf("couldn't m_pullup\n");
1090 						LEAVE(ENOBUFS);
1091 					}
1092 				}
1093 			}
1094 			if (m->m_len != m->m_pkthdr.len) {
1095 				/*
1096 				 * It's not all in one piece.
1097 				 * We need to do extra work.
1098 				 * Put it into a cluster.
1099 				 */
1100 				struct mbuf *n;
1101 				n = m_dup(m, M_DONTWAIT);
1102 				m_freem(m);
1103 				m = n;
1104 				if (m) {
1105 					/* just check we got a cluster */
1106 					if (m->m_len != m->m_pkthdr.len) {
1107 						m_freem(m);
1108 						m = NULL;
1109 					}
1110 				}
1111 				if (m == NULL) {
1112 					printf("packet fragmented\n");
1113 					LEAVE(EMSGSIZE);
1114 				}
1115 			}
1116 			wh = mtod(m, struct pppoe_full_hdr *);
1117 			length = ntohs(wh->ph.length);
1118 			ph = &wh->ph;
1119 			session = ntohs(wh->ph.sid);
1120 			code = wh->ph.code;
1121 
1122 			switch(code) {
1123 			case	PADI_CODE:
1124 				/*
1125 				 * We are a server:
1126 				 * Look for a hook with the required service
1127 				 * and send the ENTIRE packet up there.
1128 				 * It should come back to a new hook in
1129 				 * PRIMED state. Look there for further
1130 				 * processing.
1131 				 */
1132 				tag = get_tag(ph, PTT_SRV_NAME);
1133 				if (tag == NULL) {
1134 					printf("no service tag\n");
1135 					LEAVE(ENETUNREACH);
1136 				}
1137 				sendhook = pppoe_match_svc(NG_HOOK_NODE(hook),
1138 			    		tag->tag_data, ntohs(tag->tag_len),
1139 					NG_MATCH_ANY);
1140 				if (sendhook) {
1141 					NG_FWD_NEW_DATA(error, item,
1142 								sendhook, m);
1143 				} else {
1144 					LEAVE(ENETUNREACH);
1145 				}
1146 				break;
1147 			case	PADO_CODE:
1148 				/*
1149 				 * We are a client:
1150 				 * Use the host_uniq tag to find the
1151 				 * hook this is in response to.
1152 				 * Received #2, now send #3
1153 				 * For now simply accept the first we receive.
1154 				 */
1155 				utag = get_tag(ph, PTT_HOST_UNIQ);
1156 				if ((utag == NULL)
1157 				|| (ntohs(utag->tag_len) != sizeof(sp))) {
1158 					printf("no host unique field\n");
1159 					LEAVE(ENETUNREACH);
1160 				}
1161 
1162 				sendhook = pppoe_finduniq(node, utag);
1163 				if (sendhook == NULL) {
1164 					printf("no matching session\n");
1165 					LEAVE(ENETUNREACH);
1166 				}
1167 
1168 				/*
1169 				 * Check the session is in the right state.
1170 				 * It needs to be in PPPOE_SINIT.
1171 				 */
1172 				sp = NG_HOOK_PRIVATE(sendhook);
1173 				if (sp->state != PPPOE_SINIT) {
1174 					printf("session in wrong state\n");
1175 					LEAVE(ENETUNREACH);
1176 				}
1177 				neg = sp->neg;
1178 				untimeout(pppoe_ticker, sendhook,
1179 				    neg->timeout_handle);
1180 
1181 				/*
1182 				 * This is the first time we hear
1183 				 * from the server, so note it's
1184 				 * unicast address, replacing the
1185 				 * broadcast address .
1186 				 */
1187 				bcopy(wh->eh.ether_shost,
1188 					neg->pkt->pkt_header.eh.ether_dhost,
1189 					ETHER_ADDR_LEN);
1190 				neg->timeout = 0;
1191 				neg->pkt->pkt_header.ph.code = PADR_CODE;
1192 				init_tags(sp);
1193 				insert_tag(sp, utag);      /* Host Unique */
1194 				if ((tag = get_tag(ph, PTT_AC_COOKIE)))
1195 					insert_tag(sp, tag); /* return cookie */
1196 				if ((tag = get_tag(ph, PTT_AC_NAME))) {
1197 					insert_tag(sp, tag); /* return it */
1198 					send_acname(sp, tag);
1199 				}
1200 				insert_tag(sp, &neg->service.hdr); /* Service */
1201 				scan_tags(sp, ph);
1202 				make_packet(sp);
1203 				sp->state = PPPOE_SREQ;
1204 				sendpacket(sp);
1205 				break;
1206 			case	PADR_CODE:
1207 
1208 				/*
1209 				 * We are a server:
1210 				 * Use the ac_cookie tag to find the
1211 				 * hook this is in response to.
1212 				 */
1213 				utag = get_tag(ph, PTT_AC_COOKIE);
1214 				if ((utag == NULL)
1215 				|| (ntohs(utag->tag_len) != sizeof(sp))) {
1216 					LEAVE(ENETUNREACH);
1217 				}
1218 
1219 				sendhook = pppoe_finduniq(node, utag);
1220 				if (sendhook == NULL) {
1221 					LEAVE(ENETUNREACH);
1222 				}
1223 
1224 				/*
1225 				 * Check the session is in the right state.
1226 				 * It needs to be in PPPOE_SOFFER
1227 				 * or PPPOE_NEWCONNECTED. If the latter,
1228 				 * then this is a retry by the client.
1229 				 * so be nice, and resend.
1230 				 */
1231 				sp = NG_HOOK_PRIVATE(sendhook);
1232 				if (sp->state == PPPOE_NEWCONNECTED) {
1233 					/*
1234 					 * Whoa! drop back to resend that
1235 					 * PADS packet.
1236 					 * We should still have a copy of it.
1237 					 */
1238 					sp->state = PPPOE_SOFFER;
1239 				}
1240 				if (sp->state != PPPOE_SOFFER) {
1241 					LEAVE (ENETUNREACH);
1242 					break;
1243 				}
1244 				neg = sp->neg;
1245 				untimeout(pppoe_ticker, sendhook,
1246 				    neg->timeout_handle);
1247 				neg->pkt->pkt_header.ph.code = PADS_CODE;
1248 				if (sp->Session_ID == 0)
1249 					neg->pkt->pkt_header.ph.sid =
1250 					    htons(sp->Session_ID
1251 						= get_new_sid(node));
1252 				send_sessionid(sp);
1253 				neg->timeout = 0;
1254 				/*
1255 				 * start working out the tags to respond with.
1256 				 */
1257 				init_tags(sp);
1258 				insert_tag(sp, &neg->ac_name.hdr); /* AC_NAME */
1259 				if ((tag = get_tag(ph, PTT_SRV_NAME)))
1260 					insert_tag(sp, tag);/* return service */
1261 				if ((tag = get_tag(ph, PTT_HOST_UNIQ)))
1262 					insert_tag(sp, tag); /* return it */
1263 				insert_tag(sp, utag);	/* ac_cookie */
1264 				scan_tags(sp, ph);
1265 				make_packet(sp);
1266 				sp->state = PPPOE_NEWCONNECTED;
1267 				sendpacket(sp);
1268 				/*
1269 				 * Having sent the last Negotiation header,
1270 				 * Set up the stored packet header to
1271 				 * be correct for the actual session.
1272 				 * But keep the negotialtion stuff
1273 				 * around in case we need to resend this last
1274 				 * packet. We'll discard it when we move
1275 				 * from NEWCONNECTED to CONNECTED
1276 				 */
1277 				sp->pkt_hdr = neg->pkt->pkt_header;
1278 				/* Configure ethertype depending on what
1279 				 * ethertype was used at discovery phase */
1280 				if (sp->pkt_hdr.eh.ether_type ==
1281 				    ETHERTYPE_PPPOE_STUPID_DISC)
1282 					sp->pkt_hdr.eh.ether_type
1283 						= ETHERTYPE_PPPOE_STUPID_SESS;
1284 				else
1285 					sp->pkt_hdr.eh.ether_type
1286 						= ETHERTYPE_PPPOE_SESS;
1287 				sp->pkt_hdr.ph.code = 0;
1288 				pppoe_send_event(sp, NGM_PPPOE_SUCCESS);
1289 				break;
1290 			case	PADS_CODE:
1291 				/*
1292 				 * We are a client:
1293 				 * Use the host_uniq tag to find the
1294 				 * hook this is in response to.
1295 				 * take the session ID and store it away.
1296 				 * Also make sure the pre-made header is
1297 				 * correct and set us into Session mode.
1298 				 */
1299 				utag = get_tag(ph, PTT_HOST_UNIQ);
1300 				if ((utag == NULL)
1301 				|| (ntohs(utag->tag_len) != sizeof(sp))) {
1302 					LEAVE (ENETUNREACH);
1303 					break;
1304 				}
1305 				sendhook = pppoe_finduniq(node, utag);
1306 				if (sendhook == NULL) {
1307 					LEAVE(ENETUNREACH);
1308 				}
1309 
1310 				/*
1311 				 * Check the session is in the right state.
1312 				 * It needs to be in PPPOE_SREQ.
1313 				 */
1314 				sp = NG_HOOK_PRIVATE(sendhook);
1315 				if (sp->state != PPPOE_SREQ) {
1316 					LEAVE(ENETUNREACH);
1317 				}
1318 				neg = sp->neg;
1319 				untimeout(pppoe_ticker, sendhook,
1320 				    neg->timeout_handle);
1321 				neg->pkt->pkt_header.ph.sid = wh->ph.sid;
1322 				sp->Session_ID = ntohs(wh->ph.sid);
1323 				send_sessionid(sp);
1324 				neg->timeout = 0;
1325 				sp->state = PPPOE_CONNECTED;
1326 				/*
1327 				 * Now we have gone to Connected mode,
1328 				 * Free all resources needed for
1329 				 * negotiation.
1330 				 * Keep a copy of the header we will be using.
1331 				 */
1332 				sp->pkt_hdr = neg->pkt->pkt_header;
1333 				if (privp->mode->id == PPPOE_NONSTANDARD)
1334 					sp->pkt_hdr.eh.ether_type
1335 						= ETHERTYPE_PPPOE_STUPID_SESS;
1336 				else
1337 					sp->pkt_hdr.eh.ether_type
1338 						= ETHERTYPE_PPPOE_SESS;
1339 				sp->pkt_hdr.ph.code = 0;
1340 				m_freem(neg->m);
1341 				FREE(sp->neg, M_NETGRAPH_PPPOE);
1342 				sp->neg = NULL;
1343 				pppoe_send_event(sp, NGM_PPPOE_SUCCESS);
1344 				break;
1345 			case	PADT_CODE:
1346 				/*
1347 				 * Send a 'close' message to the controlling
1348 				 * process (the one that set us up);
1349 				 * And then tear everything down.
1350 				 *
1351 				 * Find matching peer/session combination.
1352 				 */
1353 				sendhook = pppoe_findsession(node, wh);
1354 				if (sendhook == NULL) {
1355 					LEAVE(ENETUNREACH);
1356 				}
1357 				/* send message to creator */
1358 				/* close hook */
1359 				if (sendhook) {
1360 					ng_rmhook_self(sendhook);
1361 				}
1362 				break;
1363 			default:
1364 				LEAVE(EPFNOSUPPORT);
1365 			}
1366 			break;
1367 		case	ETHERTYPE_PPPOE_STUPID_SESS:
1368 		case	ETHERTYPE_PPPOE_SESS:
1369 			/*
1370 			 * find matching peer/session combination.
1371 			 */
1372 			sendhook = pppoe_findsession(node, wh);
1373 			if (sendhook == NULL) {
1374 				LEAVE (ENETUNREACH);
1375 				break;
1376 			}
1377 			sp = NG_HOOK_PRIVATE(sendhook);
1378 			m_adj(m, sizeof(*wh));
1379 			if (m->m_pkthdr.len < length) {
1380 				/* Packet too short, dump it */
1381 				LEAVE(EMSGSIZE);
1382 			}
1383 
1384 			/* Also need to trim excess at the end */
1385 			if (m->m_pkthdr.len > length) {
1386 				m_adj(m, -((int)(m->m_pkthdr.len - length)));
1387 			}
1388 			if ( sp->state != PPPOE_CONNECTED) {
1389 				if (sp->state == PPPOE_NEWCONNECTED) {
1390 					sp->state = PPPOE_CONNECTED;
1391 					/*
1392 					 * Now we have gone to Connected mode,
1393 					 * Free all resources needed for
1394 					 * negotiation. Be paranoid about
1395 					 * whether there may be a timeout.
1396 					 */
1397 					m_freem(sp->neg->m);
1398 					untimeout(pppoe_ticker, sendhook,
1399 				    		sp->neg->timeout_handle);
1400 					FREE(sp->neg, M_NETGRAPH_PPPOE);
1401 					sp->neg = NULL;
1402 				} else {
1403 					LEAVE (ENETUNREACH);
1404 					break;
1405 				}
1406 			}
1407 			NG_FWD_NEW_DATA( error, item, sendhook, m);
1408 			break;
1409 		default:
1410 			LEAVE(EPFNOSUPPORT);
1411 		}
1412 	} else {
1413 		/*
1414 		 * 	Not ethernet or debug hook..
1415 		 *
1416 		 * The packet has come in on a normal hook.
1417 		 * We need to find out what kind of hook,
1418 		 * So we can decide how to handle it.
1419 		 * Check the hook's state.
1420 		 */
1421 		sp = NG_HOOK_PRIVATE(hook);
1422 		switch (sp->state) {
1423 		case	PPPOE_NEWCONNECTED:
1424 		case	PPPOE_CONNECTED: {
1425 			static const u_char addrctrl[] = { 0xff, 0x03 };
1426 			struct pppoe_full_hdr *wh;
1427 
1428 			/*
1429 			 * Remove PPP address and control fields, if any.
1430 			 * For example, ng_ppp(4) always sends LCP packets
1431 			 * with address and control fields as required by
1432 			 * generic PPP. PPPoE is an exception to the rule.
1433 			 */
1434 			if (m->m_pkthdr.len >= 2) {
1435 				if (m->m_len < 2 && !(m = m_pullup(m, 2)))
1436 					LEAVE(ENOBUFS);
1437 				if (bcmp(mtod(m, u_char *), addrctrl, 2) == 0)
1438 					m_adj(m, 2);
1439 			}
1440 			/*
1441 			 * Bang in a pre-made header, and set the length up
1442 			 * to be correct. Then send it to the ethernet driver.
1443 			 * But first correct the length.
1444 			 */
1445 			sp->pkt_hdr.ph.length = htons((short)(m->m_pkthdr.len));
1446 			M_PREPEND(m, sizeof(*wh), M_DONTWAIT);
1447 			if (m == NULL) {
1448 				LEAVE(ENOBUFS);
1449 			}
1450 			wh = mtod(m, struct pppoe_full_hdr *);
1451 			bcopy(&sp->pkt_hdr, wh, sizeof(*wh));
1452 			NG_FWD_NEW_DATA( error, item, privp->ethernet_hook, m);
1453 			privp->packets_out++;
1454 			break;
1455 			}
1456 		case	PPPOE_PRIMED:
1457 			/*
1458 			 * A PADI packet is being returned by the application
1459 			 * that has set up this hook. This indicates that it
1460 			 * wants us to offer service.
1461 			 */
1462 			neg = sp->neg;
1463 			if (m->m_len < sizeof(*wh)) {
1464 				m = m_pullup(m, sizeof(*wh));
1465 				if (m == NULL) {
1466 					LEAVE(ENOBUFS);
1467 				}
1468 			}
1469 			wh = mtod(m, struct pppoe_full_hdr *);
1470 			ph = &wh->ph;
1471 			session = ntohs(wh->ph.sid);
1472 			length = ntohs(wh->ph.length);
1473 			code = wh->ph.code;
1474 			/* Use peers mode in session */
1475 			neg->pkt->pkt_header.eh.ether_type = wh->eh.ether_type;
1476 			if ( code != PADI_CODE) {
1477 				LEAVE(EINVAL);
1478 			};
1479 			untimeout(pppoe_ticker, hook,
1480 				    neg->timeout_handle);
1481 
1482 			/*
1483 			 * This is the first time we hear
1484 			 * from the client, so note it's
1485 			 * unicast address, replacing the
1486 			 * broadcast address.
1487 			 */
1488 			bcopy(wh->eh.ether_shost,
1489 				neg->pkt->pkt_header.eh.ether_dhost,
1490 				ETHER_ADDR_LEN);
1491 			sp->state = PPPOE_SOFFER;
1492 			neg->timeout = 0;
1493 			neg->pkt->pkt_header.ph.code = PADO_CODE;
1494 
1495 			/*
1496 			 * start working out the tags to respond with.
1497 			 */
1498 			uniqtag.hdr.tag_type = PTT_AC_COOKIE;
1499 			uniqtag.hdr.tag_len = htons((u_int16_t)sizeof(sp));
1500 			uniqtag.data.pointer = sp;
1501 			init_tags(sp);
1502 			insert_tag(sp, &neg->ac_name.hdr); /* AC_NAME */
1503 			if ((tag = get_tag(ph, PTT_SRV_NAME)))
1504 				insert_tag(sp, tag);	  /* return service */
1505 			/*
1506 			 * If we have a NULL service request
1507 			 * and have an extra service defined in this hook,
1508 			 * then also add a tag for the extra service.
1509 			 * XXX this is a hack. eventually we should be able
1510 			 * to support advertising many services, not just one
1511 			 */
1512 			if (((tag == NULL) || (tag->tag_len == 0))
1513 			&& (neg->service.hdr.tag_len != 0)) {
1514 				insert_tag(sp, &neg->service.hdr); /* SERVICE */
1515 			}
1516 			if ((tag = get_tag(ph, PTT_HOST_UNIQ)))
1517 				insert_tag(sp, tag); /* returned hostunique */
1518 			insert_tag(sp, &uniqtag.hdr);
1519 			scan_tags(sp, ph);
1520 			make_packet(sp);
1521 			sendpacket(sp);
1522 			break;
1523 
1524 		/*
1525 		 * Packets coming from the hook make no sense
1526 		 * to sessions in these states. Throw them away.
1527 		 */
1528 		case	PPPOE_SINIT:
1529 		case	PPPOE_SREQ:
1530 		case	PPPOE_SOFFER:
1531 		case	PPPOE_SNONE:
1532 		case	PPPOE_LISTENING:
1533 		case	PPPOE_DEAD:
1534 		default:
1535 			LEAVE(ENETUNREACH);
1536 		}
1537 	}
1538 quit:
1539 	if (item)
1540 		NG_FREE_ITEM(item);
1541 	NG_FREE_M(m);
1542 	return error;
1543 }
1544 
1545 /*
1546  * Do local shutdown processing..
1547  * If we are a persistant device, we might refuse to go away, and
1548  * we'd only remove our links and reset ourself.
1549  */
1550 static int
1551 ng_pppoe_shutdown(node_p node)
1552 {
1553 	const priv_p privdata = NG_NODE_PRIVATE(node);
1554 
1555 AAA
1556 	NG_NODE_SET_PRIVATE(node, NULL);
1557 	NG_NODE_UNREF(privdata->node);
1558 	FREE(privdata, M_NETGRAPH_PPPOE);
1559 	return (0);
1560 }
1561 
1562 /*
1563  * This is called once we've already connected a new hook to the other node.
1564  * It gives us a chance to balk at the last minute.
1565  */
1566 static int
1567 ng_pppoe_connect(hook_p hook)
1568 {
1569 	/* be really amiable and just say "YUP that's OK by me! " */
1570 	return (0);
1571 }
1572 
1573 /*
1574  * Hook disconnection
1575  *
1576  * Clean up all dangling links and information about the session/hook.
1577  * For this type, removal of the last link destroys the node
1578  */
1579 static int
1580 ng_pppoe_disconnect(hook_p hook)
1581 {
1582 	node_p node = NG_HOOK_NODE(hook);
1583 	priv_p privp = NG_NODE_PRIVATE(node);
1584 	sessp	sp;
1585 	int 	hooks;
1586 
1587 AAA
1588 	hooks = NG_NODE_NUMHOOKS(node); /* this one already not counted */
1589 	if (NG_HOOK_PRIVATE(hook) == &privp->debug_hook) {
1590 		privp->debug_hook = NULL;
1591 	} else if (NG_HOOK_PRIVATE(hook) == &privp->ethernet_hook) {
1592 		privp->ethernet_hook = NULL;
1593 		if (NG_NODE_IS_VALID(node))
1594 			ng_rmnode_self(node);
1595 	} else {
1596 		sp = NG_HOOK_PRIVATE(hook);
1597 		if (sp->state != PPPOE_SNONE ) {
1598 			pppoe_send_event(sp, NGM_PPPOE_CLOSE);
1599 		}
1600 		/*
1601 		 * According to the spec, if we are connected,
1602 		 * we should send a DISC packet if we are shutting down
1603 		 * a session.
1604 		 */
1605 		if ((privp->ethernet_hook)
1606 		&& ((sp->state == PPPOE_CONNECTED)
1607 		 || (sp->state == PPPOE_NEWCONNECTED))) {
1608 			struct mbuf *m;
1609 			struct pppoe_full_hdr *wh;
1610 			struct pppoe_tag *tag;
1611 			int	msglen = strlen(SIGNOFF);
1612 			int error = 0;
1613 
1614 			/* revert the stored header to DISC/PADT mode */
1615 		 	wh = &sp->pkt_hdr;
1616 			wh->ph.code = PADT_CODE;
1617 			/* Configure ethertype depending on what was used during
1618 			 * sessions stage. */
1619 			if (sp->pkt_hdr.eh.ether_type ==
1620 			    ETHERTYPE_PPPOE_STUPID_SESS)
1621 				wh->eh.ether_type = ETHERTYPE_PPPOE_STUPID_DISC;
1622 			else
1623 				wh->eh.ether_type = ETHERTYPE_PPPOE_DISC;
1624 
1625 			/* generate a packet of that type */
1626 			MGETHDR(m, M_DONTWAIT, MT_DATA);
1627 			if(m == NULL)
1628 				printf("pppoe: Session out of mbufs\n");
1629 			else {
1630 				m->m_pkthdr.rcvif = NULL;
1631 				m->m_pkthdr.len = m->m_len = sizeof(*wh);
1632 				bcopy((caddr_t)wh, mtod(m, caddr_t),
1633 				    sizeof(*wh));
1634 				/*
1635 				 * Add a General error message and adjust
1636 				 * sizes
1637 				 */
1638 				wh = mtod(m, struct pppoe_full_hdr *);
1639 				tag = wh->ph.tag;
1640 				tag->tag_type = PTT_GEN_ERR;
1641 				tag->tag_len = htons((u_int16_t)msglen);
1642 				strncpy(tag->tag_data, SIGNOFF, msglen);
1643 				m->m_pkthdr.len = (m->m_len += sizeof(*tag) +
1644 				    msglen);
1645 				wh->ph.length = htons(sizeof(*tag) + msglen);
1646 				NG_SEND_DATA_ONLY(error,
1647 					privp->ethernet_hook, m);
1648 			}
1649 		}
1650 		/*
1651 		 * As long as we have somewhere to store the timeout handle,
1652 		 * we may have a timeout pending.. get rid of it.
1653 		 */
1654 		if (sp->neg) {
1655 			untimeout(pppoe_ticker, hook, sp->neg->timeout_handle);
1656 			if (sp->neg->m)
1657 				m_freem(sp->neg->m);
1658 			FREE(sp->neg, M_NETGRAPH_PPPOE);
1659 		}
1660 		FREE(sp, M_NETGRAPH_PPPOE);
1661 		NG_HOOK_SET_PRIVATE(hook, NULL);
1662 		/* work out how many session hooks there are */
1663 		/* Node goes away on last session hook removal */
1664 		if (privp->ethernet_hook) hooks -= 1;
1665 		if (privp->debug_hook) hooks -= 1;
1666 	}
1667 	if ((NG_NODE_NUMHOOKS(node) == 0)
1668 	&& (NG_NODE_IS_VALID(node)))
1669 		ng_rmnode_self(node);
1670 	return (0);
1671 }
1672 
1673 /*
1674  * timeouts come here.
1675  */
1676 static void
1677 pppoe_ticker(void *arg)
1678 {
1679 	int s = splnet();
1680 	hook_p hook = arg;
1681 	sessp	sp = NG_HOOK_PRIVATE(hook);
1682 	negp	neg = sp->neg;
1683 	int	error = 0;
1684 	struct mbuf *m0 = NULL;
1685 	priv_p privp = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
1686 
1687 AAA
1688 	switch(sp->state) {
1689 		/*
1690 		 * resend the last packet, using an exponential backoff.
1691 		 * After a period of time, stop growing the backoff,
1692 		 * and either leave it, or revert to the start.
1693 		 */
1694 	case	PPPOE_SINIT:
1695 	case	PPPOE_SREQ:
1696 		/* timeouts on these produce resends */
1697 		m0 = m_copypacket(sp->neg->m, M_DONTWAIT);
1698 		NG_SEND_DATA_ONLY( error, privp->ethernet_hook, m0);
1699 		neg->timeout_handle = timeout(pppoe_ticker,
1700 					hook, neg->timeout * hz);
1701 		if ((neg->timeout <<= 1) > PPPOE_TIMEOUT_LIMIT) {
1702 			if (sp->state == PPPOE_SREQ) {
1703 				/* revert to SINIT mode */
1704 				pppoe_start(sp);
1705 			} else {
1706 				neg->timeout = PPPOE_TIMEOUT_LIMIT;
1707 			}
1708 		}
1709 		break;
1710 	case	PPPOE_PRIMED:
1711 	case	PPPOE_SOFFER:
1712 		/* a timeout on these says "give up" */
1713 		ng_rmhook_self(hook);
1714 		break;
1715 	default:
1716 		/* timeouts have no meaning in other states */
1717 		printf("pppoe: unexpected timeout\n");
1718 	}
1719 	splx(s);
1720 }
1721 
1722 
1723 static void
1724 sendpacket(sessp sp)
1725 {
1726 	int	error = 0;
1727 	struct mbuf *m0 = NULL;
1728 	hook_p hook = sp->hook;
1729 	negp	neg = sp->neg;
1730 	priv_p	privp = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
1731 
1732 AAA
1733 	switch(sp->state) {
1734 	case	PPPOE_LISTENING:
1735 	case	PPPOE_DEAD:
1736 	case	PPPOE_SNONE:
1737 	case	PPPOE_CONNECTED:
1738 		printf("pppoe: sendpacket: unexpected state\n");
1739 		break;
1740 
1741 	case	PPPOE_NEWCONNECTED:
1742 		/* send the PADS without a timeout - we're now connected */
1743 		m0 = m_copypacket(sp->neg->m, M_DONTWAIT);
1744 		NG_SEND_DATA_ONLY( error, privp->ethernet_hook, m0);
1745 		break;
1746 
1747 	case	PPPOE_PRIMED:
1748 		/* No packet to send, but set up the timeout */
1749 		neg->timeout_handle = timeout(pppoe_ticker,
1750 					hook, PPPOE_OFFER_TIMEOUT * hz);
1751 		break;
1752 
1753 	case	PPPOE_SOFFER:
1754 		/*
1755 		 * send the offer but if they don't respond
1756 		 * in PPPOE_OFFER_TIMEOUT seconds, forget about it.
1757 		 */
1758 		m0 = m_copypacket(sp->neg->m, M_DONTWAIT);
1759 		NG_SEND_DATA_ONLY( error, privp->ethernet_hook, m0);
1760 		neg->timeout_handle = timeout(pppoe_ticker,
1761 					hook, PPPOE_OFFER_TIMEOUT * hz);
1762 		break;
1763 
1764 	case	PPPOE_SINIT:
1765 	case	PPPOE_SREQ:
1766 		m0 = m_copypacket(sp->neg->m, M_DONTWAIT);
1767 		NG_SEND_DATA_ONLY( error, privp->ethernet_hook, m0);
1768 		neg->timeout_handle = timeout(pppoe_ticker, hook,
1769 					(hz * PPPOE_INITIAL_TIMEOUT));
1770 		neg->timeout = PPPOE_INITIAL_TIMEOUT * 2;
1771 		break;
1772 
1773 	default:
1774 		error = EINVAL;
1775 		printf("pppoe: timeout: bad state\n");
1776 	}
1777 	/* return (error); */
1778 }
1779 
1780 /*
1781  * Parse an incoming packet to see if any tags should be copied to the
1782  * output packet. Don't do any tags that have been handled in the main
1783  * state machine.
1784  */
1785 static const struct pppoe_tag*
1786 scan_tags(sessp	sp, const struct pppoe_hdr* ph)
1787 {
1788 	const char *const end = (const char *)next_tag(ph);
1789 	const char *ptn;
1790 	const struct pppoe_tag *pt = &ph->tag[0];
1791 	/*
1792 	 * Keep processing tags while a tag header will still fit.
1793 	 */
1794 AAA
1795 	while((const char*)(pt + 1) <= end) {
1796 		/*
1797 		 * If the tag data would go past the end of the packet, abort.
1798 		 */
1799 		ptn = (((const char *)(pt + 1)) + ntohs(pt->tag_len));
1800 		if(ptn > end)
1801 			return NULL;
1802 
1803 		switch (pt->tag_type) {
1804 		case	PTT_RELAY_SID:
1805 			insert_tag(sp, pt);
1806 			break;
1807 		case	PTT_EOL:
1808 			return NULL;
1809 		case	PTT_SRV_NAME:
1810 		case	PTT_AC_NAME:
1811 		case	PTT_HOST_UNIQ:
1812 		case	PTT_AC_COOKIE:
1813 		case	PTT_VENDOR:
1814 		case	PTT_SRV_ERR:
1815 		case	PTT_SYS_ERR:
1816 		case	PTT_GEN_ERR:
1817 			break;
1818 		}
1819 		pt = (const struct pppoe_tag*)ptn;
1820 	}
1821 	return NULL;
1822 }
1823 
1824 static	int
1825 pppoe_send_event(sessp sp, enum cmd cmdid)
1826 {
1827 	int error;
1828 	struct ng_mesg *msg;
1829 	struct ngpppoe_sts *sts;
1830 
1831 AAA
1832 	NG_MKMESSAGE(msg, NGM_PPPOE_COOKIE, cmdid,
1833 			sizeof(struct ngpppoe_sts), M_NOWAIT);
1834 	if (msg == NULL)
1835 		return (ENOMEM);
1836 	sts = (struct ngpppoe_sts *)msg->data;
1837 	strncpy(sts->hook, NG_HOOK_NAME(sp->hook), NG_HOOKSIZ);
1838 	NG_SEND_MSG_ID(error, NG_HOOK_NODE(sp->hook), msg, sp->creator, 0);
1839 	return (error);
1840 }
1841