1/*
2 * ng_pptpgre.c
3 */
4
5/*-
6 * Copyright (c) 1996-1999 Whistle Communications, Inc.
7 * All rights reserved.
8 *
9 * Subject to the following obligations and disclaimer of warranty, use and
10 * redistribution of this software, in source or object code forms, with or
11 * without modifications are expressly permitted by Whistle Communications;
12 * provided, however, that:
13 * 1. Any and all reproductions of the source or object code must include the
14 *    copyright notice above and the following disclaimer of warranties; and
15 * 2. No rights are granted, in any manner or form, to use Whistle
16 *    Communications, Inc. trademarks, including the mark "WHISTLE
17 *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
18 *    such appears in the above copyright notice or in the software.
19 *
20 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
21 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
22 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
23 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
25 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
26 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
27 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
28 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
29 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
30 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
36 * OF SUCH DAMAGE.
37 *
38 * Author: Archie Cobbs <archie@freebsd.org>
39 * $Whistle: ng_pptpgre.c,v 1.7 1999/12/08 00:10:06 archie Exp $
40 */
41
42/*
43 * PPTP/GRE netgraph node type.
44 *
45 * This node type does the GRE encapsulation as specified for the PPTP
46 * protocol (RFC 2637, section 4).  This includes sequencing and
47 * retransmission of frames, but not the actual packet delivery nor
48 * any of the TCP control stream protocol.
49 *
50 * The "upper" hook of this node is suitable for attaching to a "ppp"
51 * node link hook.  The "lower" hook of this node is suitable for attaching
52 * to a "ksocket" node on hook "inet/raw/gre".
53 */
54
55#include <sys/param.h>
56#include <sys/systm.h>
57#include <sys/kernel.h>
58#include <sys/time.h>
59#include <sys/lock.h>
60#include <sys/malloc.h>
61#include <sys/mbuf.h>
62#include <sys/mutex.h>
63#include <sys/endian.h>
64#include <sys/errno.h>
65#include <sys/sysctl.h>
66
67#include <netinet/in.h>
68#include <netinet/in_systm.h>
69#include <netinet/ip.h>
70
71#include <netgraph/ng_message.h>
72#include <netgraph/netgraph.h>
73#include <netgraph/ng_parse.h>
74#include <netgraph/ng_pptpgre.h>
75
76#ifdef NG_SEPARATE_MALLOC
77static MALLOC_DEFINE(M_NETGRAPH_PPTP, "netgraph_pptp", "netgraph pptpgre node");
78#else
79#define M_NETGRAPH_PPTP M_NETGRAPH
80#endif
81
82/* GRE packet format, as used by PPTP */
83struct greheader {
84#if BYTE_ORDER == LITTLE_ENDIAN
85	u_char		recursion:3;		/* recursion control */
86	u_char		ssr:1;			/* strict source route */
87	u_char		hasSeq:1;		/* sequence number present */
88	u_char		hasKey:1;		/* key present */
89	u_char		hasRoute:1;		/* routing present */
90	u_char		hasSum:1;		/* checksum present */
91	u_char		vers:3;			/* version */
92	u_char		flags:4;		/* flags */
93	u_char		hasAck:1;		/* acknowlege number present */
94#elif BYTE_ORDER == BIG_ENDIAN
95	u_char		hasSum:1;		/* checksum present */
96	u_char		hasRoute:1;		/* routing present */
97	u_char		hasKey:1;		/* key present */
98	u_char		hasSeq:1;		/* sequence number present */
99	u_char		ssr:1;			/* strict source route */
100	u_char		recursion:3;		/* recursion control */
101	u_char		hasAck:1;		/* acknowlege number present */
102	u_char		flags:4;		/* flags */
103	u_char		vers:3;			/* version */
104#else
105#error BYTE_ORDER is not defined properly
106#endif
107	u_int16_t	proto;			/* protocol (ethertype) */
108	u_int16_t	length;			/* payload length */
109	u_int16_t	cid;			/* call id */
110	u_int32_t	data[0];		/* opt. seq, ack, then data */
111};
112
113/* The PPTP protocol ID used in the GRE 'proto' field */
114#define PPTP_GRE_PROTO		0x880b
115
116/* Bits that must be set a certain way in all PPTP/GRE packets */
117#define PPTP_INIT_VALUE		((0x2001 << 16) | PPTP_GRE_PROTO)
118#define PPTP_INIT_MASK		0xef7fffff
119
120/* Min and max packet length */
121#define PPTP_MAX_PAYLOAD	(0xffff - sizeof(struct greheader) - 8)
122
123/* All times are scaled by this (PPTP_TIME_SCALE time units = 1 sec.) */
124#define PPTP_TIME_SCALE		1024			/* milliseconds */
125typedef u_int64_t		pptptime_t;
126
127/* Acknowledgment timeout parameters and functions */
128#define PPTP_XMIT_WIN		16			/* max xmit window */
129#define PPTP_MIN_TIMEOUT	(PPTP_TIME_SCALE / 83)	/* 12 milliseconds */
130#define PPTP_MAX_TIMEOUT	(3 * PPTP_TIME_SCALE)	/* 3 seconds */
131
132#define PPTP_REORDER_TIMEOUT	1
133
134/* When we receive a packet, we wait to see if there's an outgoing packet
135   we can piggy-back the ACK off of. These parameters determine the minimum
136   and maxmimum length of time we're willing to wait in order to do that.
137   These have no effect unless "enableDelayedAck" is turned on. */
138#define PPTP_MIN_ACK_DELAY	(PPTP_TIME_SCALE / 500)	/* 2 milliseconds */
139#define PPTP_MAX_ACK_DELAY	(PPTP_TIME_SCALE / 2)	/* 500 milliseconds */
140
141/* See RFC 2637 section 4.4 */
142#define PPTP_ACK_ALPHA(x)	(((x) + 4) >> 3)	/* alpha = 0.125 */
143#define PPTP_ACK_BETA(x)	(((x) + 2) >> 2)	/* beta = 0.25 */
144#define PPTP_ACK_CHI(x) 	((x) << 2)	/* chi = 4 */
145#define PPTP_ACK_DELTA(x) 	((x) << 1)	/* delta = 2 */
146
147#define PPTP_SEQ_DIFF(x,y)	((int32_t)(x) - (int32_t)(y))
148
149#define SESSHASHSIZE		0x0020
150#define SESSHASH(x)		(((x) ^ ((x) >> 8)) & (SESSHASHSIZE - 1))
151
152SYSCTL_NODE(_net_graph, OID_AUTO, pptpgre, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
153    "PPTPGRE");
154
155/*
156 * Reorder queue maximum length. Zero disables reorder.
157 *
158 * The node may keep reorder_max queue entries per session
159 * if reorder is enabled, plus allocate one more for short time.
160 *
161 * Be conservative in memory consumption by default.
162 * Lots of sessions with large queues can overflow M_NETGRAPH zone.
163 */
164static int reorder_max = 1; /* reorder up to two swapped packets in a row */
165SYSCTL_UINT(_net_graph_pptpgre, OID_AUTO, reorder_max, CTLFLAG_RWTUN,
166	&reorder_max, 0, "Reorder queue maximum length");
167
168static int reorder_timeout = PPTP_REORDER_TIMEOUT;
169SYSCTL_UINT(_net_graph_pptpgre, OID_AUTO, reorder_timeout, CTLFLAG_RWTUN,
170	&reorder_timeout, 0, "Reorder timeout is milliseconds");
171
172/* Packet reorder FIFO queue */
173struct ng_pptpgre_roq {
174	SLIST_ENTRY(ng_pptpgre_roq)  next;	/* next entry of the queue */
175	item_p			item;		/* netgraph item */
176	u_int32_t		seq;		/* packet sequence number */
177};
178SLIST_HEAD(ng_pptpgre_roq_head, ng_pptpgre_roq);
179typedef struct ng_pptpgre_roq_head roqh;
180
181/* We keep packet retransmit and acknowlegement state in this struct */
182struct ng_pptpgre_sess {
183	node_p			node;		/* this node pointer */
184	hook_p			hook;		/* hook to upper layers */
185	struct ng_pptpgre_conf	conf;		/* configuration info */
186	struct mtx		mtx;		/* session mutex */
187	u_int32_t		recvSeq;	/* last seq # we rcv'd */
188	u_int32_t		xmitSeq;	/* last seq # we sent */
189	u_int32_t		recvAck;	/* last seq # peer ack'd */
190	u_int32_t		xmitAck;	/* last seq # we ack'd */
191	int32_t			ato;		/* adaptive time-out value */
192	int32_t			rtt;		/* round trip time estimate */
193	int32_t			dev;		/* deviation estimate */
194	u_int16_t		xmitWin;	/* size of xmit window */
195	struct callout		sackTimer;	/* send ack timer */
196	struct callout		rackTimer;	/* recv ack timer */
197	u_int32_t		winAck;		/* seq when xmitWin will grow */
198	pptptime_t		timeSent[PPTP_XMIT_WIN];
199	LIST_ENTRY(ng_pptpgre_sess) sessions;
200	roqh			roq;		/* reorder queue head */
201	u_int8_t		roq_len;	/* reorder queue length */
202	struct callout		reorderTimer;	/* reorder timeout handler */
203};
204typedef struct ng_pptpgre_sess *hpriv_p;
205
206/* Node private data */
207struct ng_pptpgre_private {
208	hook_p			upper;		/* hook to upper layers */
209	hook_p			lower;		/* hook to lower layers */
210	struct ng_pptpgre_sess	uppersess;	/* default session for compat */
211	LIST_HEAD(, ng_pptpgre_sess) sesshash[SESSHASHSIZE];
212	struct ng_pptpgre_stats	stats;		/* node statistics */
213};
214typedef struct ng_pptpgre_private *priv_p;
215
216/* Netgraph node methods */
217static ng_constructor_t	ng_pptpgre_constructor;
218static ng_rcvmsg_t	ng_pptpgre_rcvmsg;
219static ng_shutdown_t	ng_pptpgre_shutdown;
220static ng_newhook_t	ng_pptpgre_newhook;
221static ng_rcvdata_t	ng_pptpgre_rcvdata;
222static ng_rcvdata_t	ng_pptpgre_rcvdata_lower;
223static ng_disconnect_t	ng_pptpgre_disconnect;
224
225/* Helper functions */
226static int	ng_pptpgre_xmit(hpriv_p hpriv, item_p item);
227static void	ng_pptpgre_start_send_ack_timer(hpriv_p hpriv);
228static void	ng_pptpgre_start_recv_ack_timer(hpriv_p hpriv);
229static void	ng_pptpgre_start_reorder_timer(hpriv_p hpriv);
230static void	ng_pptpgre_recv_ack_timeout(node_p node, hook_p hook,
231		    void *arg1, int arg2);
232static void	ng_pptpgre_send_ack_timeout(node_p node, hook_p hook,
233		    void *arg1, int arg2);
234static void	ng_pptpgre_reorder_timeout(node_p node, hook_p hook,
235		    void *arg1, int arg2);
236static hpriv_p	ng_pptpgre_find_session(priv_p privp, u_int16_t cid);
237static void	ng_pptpgre_reset(hpriv_p hpriv);
238static pptptime_t ng_pptpgre_time(void);
239static void	ng_pptpgre_ack(const hpriv_p hpriv);
240static int	ng_pptpgre_sendq(const hpriv_p hpriv, roqh *q,
241		    const struct ng_pptpgre_roq *st);
242
243/* Parse type for struct ng_pptpgre_conf */
244static const struct ng_parse_struct_field ng_pptpgre_conf_type_fields[]
245	= NG_PPTPGRE_CONF_TYPE_INFO;
246static const struct ng_parse_type ng_pptpgre_conf_type = {
247	&ng_parse_struct_type,
248	&ng_pptpgre_conf_type_fields,
249};
250
251/* Parse type for struct ng_pptpgre_stats */
252static const struct ng_parse_struct_field ng_pptpgre_stats_type_fields[]
253	= NG_PPTPGRE_STATS_TYPE_INFO;
254static const struct ng_parse_type ng_pptp_stats_type = {
255	&ng_parse_struct_type,
256	&ng_pptpgre_stats_type_fields
257};
258
259/* List of commands and how to convert arguments to/from ASCII */
260static const struct ng_cmdlist ng_pptpgre_cmdlist[] = {
261	{
262	  NGM_PPTPGRE_COOKIE,
263	  NGM_PPTPGRE_SET_CONFIG,
264	  "setconfig",
265	  &ng_pptpgre_conf_type,
266	  NULL
267	},
268	{
269	  NGM_PPTPGRE_COOKIE,
270	  NGM_PPTPGRE_GET_CONFIG,
271	  "getconfig",
272	  &ng_parse_hint16_type,
273	  &ng_pptpgre_conf_type
274	},
275	{
276	  NGM_PPTPGRE_COOKIE,
277	  NGM_PPTPGRE_GET_STATS,
278	  "getstats",
279	  NULL,
280	  &ng_pptp_stats_type
281	},
282	{
283	  NGM_PPTPGRE_COOKIE,
284	  NGM_PPTPGRE_CLR_STATS,
285	  "clrstats",
286	  NULL,
287	  NULL
288	},
289	{
290	  NGM_PPTPGRE_COOKIE,
291	  NGM_PPTPGRE_GETCLR_STATS,
292	  "getclrstats",
293	  NULL,
294	  &ng_pptp_stats_type
295	},
296	{ 0 }
297};
298
299/* Node type descriptor */
300static struct ng_type ng_pptpgre_typestruct = {
301	.version =	NG_ABI_VERSION,
302	.name =		NG_PPTPGRE_NODE_TYPE,
303	.constructor =	ng_pptpgre_constructor,
304	.rcvmsg =	ng_pptpgre_rcvmsg,
305	.shutdown =	ng_pptpgre_shutdown,
306	.newhook =	ng_pptpgre_newhook,
307	.rcvdata =	ng_pptpgre_rcvdata,
308	.disconnect =	ng_pptpgre_disconnect,
309	.cmdlist =	ng_pptpgre_cmdlist,
310};
311NETGRAPH_INIT(pptpgre, &ng_pptpgre_typestruct);
312
313#define ERROUT(x)	do { error = (x); goto done; } while (0)
314
315/************************************************************************
316			NETGRAPH NODE STUFF
317 ************************************************************************/
318
319/*
320 * Node type constructor
321 */
322static int
323ng_pptpgre_constructor(node_p node)
324{
325	priv_p priv;
326	int i;
327
328	/* Allocate private structure */
329	priv = malloc(sizeof(*priv), M_NETGRAPH_PPTP, M_WAITOK | M_ZERO);
330
331	NG_NODE_SET_PRIVATE(node, priv);
332
333	/* Initialize state */
334	mtx_init(&priv->uppersess.mtx, "ng_pptp", NULL, MTX_DEF);
335	ng_callout_init(&priv->uppersess.sackTimer);
336	ng_callout_init(&priv->uppersess.rackTimer);
337	priv->uppersess.node = node;
338
339	SLIST_INIT(&priv->uppersess.roq);
340	priv->uppersess.roq_len = 0;
341	ng_callout_init(&priv->uppersess.reorderTimer);
342
343	for (i = 0; i < SESSHASHSIZE; i++)
344	    LIST_INIT(&priv->sesshash[i]);
345
346	LIST_INSERT_HEAD(&priv->sesshash[0], &priv->uppersess, sessions);
347
348	/* Done */
349	return (0);
350}
351
352/*
353 * Give our OK for a hook to be added.
354 */
355static int
356ng_pptpgre_newhook(node_p node, hook_p hook, const char *name)
357{
358	const priv_p priv = NG_NODE_PRIVATE(node);
359
360	/* Check hook name */
361	if (strcmp(name, NG_PPTPGRE_HOOK_UPPER) == 0) {
362		priv->upper = hook;
363		priv->uppersess.hook = hook;
364		NG_HOOK_SET_PRIVATE(hook, &priv->uppersess);
365	} else if (strcmp(name, NG_PPTPGRE_HOOK_LOWER) == 0) {
366		priv->lower = hook;
367		NG_HOOK_SET_RCVDATA(hook, ng_pptpgre_rcvdata_lower);
368	} else {
369		static const char hexdig[16] = "0123456789abcdef";
370		const char *hex;
371		hpriv_p hpriv;
372		int i, j;
373		uint16_t cid, hash;
374
375		/* Parse hook name to get session ID */
376		if (strncmp(name, NG_PPTPGRE_HOOK_SESSION_P,
377		    sizeof(NG_PPTPGRE_HOOK_SESSION_P) - 1) != 0)
378			return (EINVAL);
379		hex = name + sizeof(NG_PPTPGRE_HOOK_SESSION_P) - 1;
380		for (cid = i = 0; i < 4; i++) {
381			for (j = 0; j < 16 && hex[i] != hexdig[j]; j++);
382			if (j == 16)
383				return (EINVAL);
384			cid = (cid << 4) | j;
385		}
386		if (hex[i] != '\0')
387			return (EINVAL);
388
389		hpriv = malloc(sizeof(*hpriv), M_NETGRAPH_PPTP, M_NOWAIT | M_ZERO);
390		if (hpriv == NULL)
391			return (ENOMEM);
392
393		/* Initialize state */
394		mtx_init(&hpriv->mtx, "ng_pptp", NULL, MTX_DEF);
395		ng_callout_init(&hpriv->sackTimer);
396		ng_callout_init(&hpriv->rackTimer);
397		hpriv->conf.cid = cid;
398		hpriv->node = node;
399		hpriv->hook = hook;
400
401		SLIST_INIT(&hpriv->roq);
402		hpriv->roq_len = 0;
403		ng_callout_init(&hpriv->reorderTimer);
404
405		NG_HOOK_SET_PRIVATE(hook, hpriv);
406
407		hash = SESSHASH(cid);
408		LIST_INSERT_HEAD(&priv->sesshash[hash], hpriv, sessions);
409	}
410
411	return (0);
412}
413
414/*
415 * Receive a control message.
416 */
417static int
418ng_pptpgre_rcvmsg(node_p node, item_p item, hook_p lasthook)
419{
420	const priv_p priv = NG_NODE_PRIVATE(node);
421	struct ng_mesg *resp = NULL;
422	int error = 0;
423	struct ng_mesg *msg;
424
425	NGI_GET_MSG(item, msg);
426	switch (msg->header.typecookie) {
427	case NGM_PPTPGRE_COOKIE:
428		switch (msg->header.cmd) {
429		case NGM_PPTPGRE_SET_CONFIG:
430		    {
431			struct ng_pptpgre_conf *const newConf =
432				(struct ng_pptpgre_conf *) msg->data;
433			hpriv_p hpriv;
434			uint16_t hash;
435
436			/* Check for invalid or illegal config */
437			if (msg->header.arglen != sizeof(*newConf))
438				ERROUT(EINVAL);
439			/* Try to find session by cid. */
440			hpriv = ng_pptpgre_find_session(priv, newConf->cid);
441			/* If not present - use upper. */
442			if (hpriv == NULL) {
443				hpriv = &priv->uppersess;
444				LIST_REMOVE(hpriv, sessions);
445				hash = SESSHASH(newConf->cid);
446				LIST_INSERT_HEAD(&priv->sesshash[hash], hpriv,
447				    sessions);
448			}
449			ng_pptpgre_reset(hpriv);	/* reset on configure */
450			hpriv->conf = *newConf;
451			break;
452		    }
453		case NGM_PPTPGRE_GET_CONFIG:
454		    {
455			hpriv_p hpriv;
456
457			if (msg->header.arglen == 2) {
458				/* Try to find session by cid. */
459	    			hpriv = ng_pptpgre_find_session(priv,
460				    *((uint16_t *)msg->data));
461				if (hpriv == NULL)
462					ERROUT(EINVAL);
463			} else if (msg->header.arglen == 0) {
464				/* Use upper. */
465				hpriv = &priv->uppersess;
466			} else
467				ERROUT(EINVAL);
468			NG_MKRESPONSE(resp, msg, sizeof(hpriv->conf), M_NOWAIT);
469			if (resp == NULL)
470				ERROUT(ENOMEM);
471			bcopy(&hpriv->conf, resp->data, sizeof(hpriv->conf));
472			break;
473		    }
474		case NGM_PPTPGRE_GET_STATS:
475		case NGM_PPTPGRE_CLR_STATS:
476		case NGM_PPTPGRE_GETCLR_STATS:
477		    {
478			if (msg->header.cmd != NGM_PPTPGRE_CLR_STATS) {
479				NG_MKRESPONSE(resp, msg,
480				    sizeof(priv->stats), M_NOWAIT);
481				if (resp == NULL)
482					ERROUT(ENOMEM);
483				bcopy(&priv->stats,
484				    resp->data, sizeof(priv->stats));
485			}
486			if (msg->header.cmd != NGM_PPTPGRE_GET_STATS)
487				bzero(&priv->stats, sizeof(priv->stats));
488			break;
489		    }
490		default:
491			error = EINVAL;
492			break;
493		}
494		break;
495	default:
496		error = EINVAL;
497		break;
498	}
499done:
500	NG_RESPOND_MSG(error, node, item, resp);
501	NG_FREE_MSG(msg);
502	return (error);
503}
504
505/*
506 * Receive incoming data on a hook.
507 */
508static int
509ng_pptpgre_rcvdata(hook_p hook, item_p item)
510{
511	const hpriv_p hpriv = NG_HOOK_PRIVATE(hook);
512	int rval;
513
514	/* If not configured, reject */
515	if (!hpriv->conf.enabled) {
516		NG_FREE_ITEM(item);
517		return (ENXIO);
518	}
519
520	mtx_lock(&hpriv->mtx);
521
522	rval = ng_pptpgre_xmit(hpriv, item);
523
524	mtx_assert(&hpriv->mtx, MA_NOTOWNED);
525
526	return (rval);
527}
528
529/*
530 * Hook disconnection
531 */
532static int
533ng_pptpgre_disconnect(hook_p hook)
534{
535	const node_p node = NG_HOOK_NODE(hook);
536	const priv_p priv = NG_NODE_PRIVATE(node);
537	const hpriv_p hpriv = NG_HOOK_PRIVATE(hook);
538
539	/* Zero out hook pointer */
540	if (hook == priv->upper) {
541		priv->upper = NULL;
542		priv->uppersess.hook = NULL;
543	} else if (hook == priv->lower) {
544		priv->lower = NULL;
545	} else {
546		/* Reset node (stops timers) */
547		ng_pptpgre_reset(hpriv);
548
549		LIST_REMOVE(hpriv, sessions);
550		mtx_destroy(&hpriv->mtx);
551		free(hpriv, M_NETGRAPH_PPTP);
552	}
553
554	/* Go away if no longer connected to anything */
555	if ((NG_NODE_NUMHOOKS(node) == 0)
556	&& (NG_NODE_IS_VALID(node)))
557		ng_rmnode_self(node);
558	return (0);
559}
560
561/*
562 * Destroy node
563 */
564static int
565ng_pptpgre_shutdown(node_p node)
566{
567	const priv_p priv = NG_NODE_PRIVATE(node);
568
569	/* Reset node (stops timers) */
570	ng_pptpgre_reset(&priv->uppersess);
571
572	LIST_REMOVE(&priv->uppersess, sessions);
573	mtx_destroy(&priv->uppersess.mtx);
574
575	free(priv, M_NETGRAPH_PPTP);
576
577	/* Decrement ref count */
578	NG_NODE_UNREF(node);
579	return (0);
580}
581
582/*************************************************************************
583		    TRANSMIT AND RECEIVE FUNCTIONS
584*************************************************************************/
585
586/*
587 * Transmit an outgoing frame, or just an ack if m is NULL.
588 */
589static int
590ng_pptpgre_xmit(hpriv_p hpriv, item_p item)
591{
592	const priv_p priv = NG_NODE_PRIVATE(hpriv->node);
593	u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)];
594	struct greheader *const gre = (struct greheader *)buf;
595	int grelen, error;
596	struct mbuf *m;
597
598	mtx_assert(&hpriv->mtx, MA_OWNED);
599
600	if (item) {
601		NGI_GET_M(item, m);
602	} else {
603		m = NULL;
604	}
605	/* Check if there's data */
606	if (m != NULL) {
607		/* Check if windowing is enabled */
608		if (hpriv->conf.enableWindowing) {
609			/* Is our transmit window full? */
610			if ((u_int32_t)PPTP_SEQ_DIFF(hpriv->xmitSeq,
611			    hpriv->recvAck) >= hpriv->xmitWin) {
612				priv->stats.xmitDrops++;
613				ERROUT(ENOBUFS);
614			}
615		}
616
617		/* Sanity check frame length */
618		if (m->m_pkthdr.len > PPTP_MAX_PAYLOAD) {
619			priv->stats.xmitTooBig++;
620			ERROUT(EMSGSIZE);
621		}
622	} else {
623		priv->stats.xmitLoneAcks++;
624	}
625
626	/* Build GRE header */
627	be32enc(gre, PPTP_INIT_VALUE);
628	be16enc(&gre->length, (m != NULL) ? m->m_pkthdr.len : 0);
629	be16enc(&gre->cid, hpriv->conf.peerCid);
630
631	/* Include sequence number if packet contains any data */
632	if (m != NULL) {
633		gre->hasSeq = 1;
634		if (hpriv->conf.enableWindowing) {
635			hpriv->timeSent[hpriv->xmitSeq - hpriv->recvAck]
636			    = ng_pptpgre_time();
637		}
638		hpriv->xmitSeq++;
639		be32enc(&gre->data[0], hpriv->xmitSeq);
640	}
641
642	/* Include acknowledgement (and stop send ack timer) if needed */
643	if (hpriv->conf.enableAlwaysAck || hpriv->xmitAck != hpriv->recvSeq) {
644		gre->hasAck = 1;
645		be32enc(&gre->data[gre->hasSeq], hpriv->recvSeq);
646		hpriv->xmitAck = hpriv->recvSeq;
647		if (hpriv->conf.enableDelayedAck)
648			ng_uncallout(&hpriv->sackTimer, hpriv->node);
649	}
650
651	/* Prepend GRE header to outgoing frame */
652	grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
653	if (m == NULL) {
654		MGETHDR(m, M_NOWAIT, MT_DATA);
655		if (m == NULL) {
656			priv->stats.memoryFailures++;
657			ERROUT(ENOBUFS);
658		}
659		m->m_len = m->m_pkthdr.len = grelen;
660		m->m_pkthdr.rcvif = NULL;
661	} else {
662		M_PREPEND(m, grelen, M_NOWAIT);
663		if (m == NULL || (m->m_len < grelen
664		    && (m = m_pullup(m, grelen)) == NULL)) {
665			priv->stats.memoryFailures++;
666			ERROUT(ENOBUFS);
667		}
668	}
669	bcopy(gre, mtod(m, u_char *), grelen);
670
671	/* Update stats */
672	priv->stats.xmitPackets++;
673	priv->stats.xmitOctets += m->m_pkthdr.len;
674
675	/*
676	 * XXX: we should reset timer only after an item has been sent
677	 * successfully.
678	 */
679	if (hpriv->conf.enableWindowing &&
680	    gre->hasSeq && hpriv->xmitSeq == hpriv->recvAck + 1)
681		ng_pptpgre_start_recv_ack_timer(hpriv);
682
683	mtx_unlock(&hpriv->mtx);
684
685	/* Deliver packet */
686	if (item) {
687		NG_FWD_NEW_DATA(error, item, priv->lower, m);
688	} else {
689		NG_SEND_DATA_ONLY(error, priv->lower, m);
690	}
691
692	return (error);
693
694done:
695	mtx_unlock(&hpriv->mtx);
696	NG_FREE_M(m);
697	if (item)
698		NG_FREE_ITEM(item);
699	return (error);
700}
701
702static void
703ng_pptpgre_ack(const hpriv_p hpriv)
704{
705	mtx_assert(&hpriv->mtx, MA_OWNED);
706	if (!(callout_pending(&hpriv->sackTimer))) {
707		/* If delayed ACK is disabled, send it now */
708		if (!hpriv->conf.enableDelayedAck) {	/* ack now */
709			ng_pptpgre_xmit(hpriv, NULL);
710			/* ng_pptpgre_xmit() drops the mutex */
711			return;
712		}
713		/* ack later */
714		ng_pptpgre_start_send_ack_timer(hpriv);
715		mtx_unlock(&hpriv->mtx);
716		return;
717	}
718	mtx_unlock(&hpriv->mtx);
719}
720
721/*
722 * Delivers packets from the queue "q" to upper layers. Frees delivered
723 * entries with the exception of one equal to "st" that is allocated
724 * on caller's stack and not on the heap.
725 */
726static int
727ng_pptpgre_sendq(const hpriv_p hpriv, roqh *q, const struct ng_pptpgre_roq *st)
728{
729	struct ng_pptpgre_roq *np;
730	struct mbuf *m;
731	int error = 0;
732
733	mtx_assert(&hpriv->mtx, MA_NOTOWNED);
734	while (!SLIST_EMPTY(q)) {
735		np = SLIST_FIRST(q);
736		SLIST_REMOVE_HEAD(q, next);
737		NGI_GET_M(np->item, m);
738		NG_FWD_NEW_DATA(error, np->item, hpriv->hook, m);
739		if (np != st)
740			free(np, M_NETGRAPH_PPTP);
741	}
742	return (error);
743}
744
745/*
746 * Handle an incoming packet.  The packet includes the IP header.
747 */
748static int
749ng_pptpgre_rcvdata_lower(hook_p hook, item_p item)
750{
751	hpriv_p hpriv;
752	node_p node = NG_HOOK_NODE(hook);
753	const priv_p priv = NG_NODE_PRIVATE(node);
754	int iphlen, grelen, extralen;
755	const struct greheader *gre;
756	const struct ip *ip;
757	int error = 0;
758	struct mbuf *m;
759
760	roqh sendq = SLIST_HEAD_INITIALIZER(sendq);  /* send queue on stack */
761	struct ng_pptpgre_roq *last = NULL;	/* last packet in the sendq */
762	struct ng_pptpgre_roq *np, *prev;
763	struct ng_pptpgre_roq temp = { { NULL }, NULL, 0 };
764	long diff;
765	u_int32_t seq;
766
767	m = NGI_M(item);
768	/* Update stats */
769	priv->stats.recvPackets++;
770	priv->stats.recvOctets += m->m_pkthdr.len;
771
772	/* Sanity check packet length */
773	if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) {
774		priv->stats.recvRunts++;
775		ERROUT(EINVAL);
776	}
777
778	/* Safely pull up the complete IP+GRE headers */
779	if (m->m_len < sizeof(*ip) + sizeof(*gre)) {
780		if ((m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) {
781			priv->stats.memoryFailures++;
782			_NGI_M(item) = NULL;
783			ERROUT(ENOBUFS);
784		}
785		_NGI_M(item) = m;
786	}
787	ip = mtod(m, const struct ip *);
788	iphlen = ip->ip_hl << 2;
789	if (m->m_len < iphlen + sizeof(*gre)) {
790		if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) {
791			priv->stats.memoryFailures++;
792			_NGI_M(item) = NULL;
793			ERROUT(ENOBUFS);
794		}
795		_NGI_M(item) = m;
796		ip = mtod(m, const struct ip *);
797	}
798	gre = (const struct greheader *)((const u_char *)ip + iphlen);
799	grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
800	if (m->m_pkthdr.len < iphlen + grelen) {
801		priv->stats.recvRunts++;
802		ERROUT(EINVAL);
803	}
804	if (m->m_len < iphlen + grelen) {
805		if ((m = m_pullup(m, iphlen + grelen)) == NULL) {
806			priv->stats.memoryFailures++;
807			_NGI_M(item) = NULL;
808			ERROUT(ENOBUFS);
809		}
810		_NGI_M(item) = m;
811		ip = mtod(m, const struct ip *);
812		gre = (const struct greheader *)((const u_char *)ip + iphlen);
813	}
814
815	/* Sanity check packet length and GRE header bits */
816	extralen = m->m_pkthdr.len
817	    - (iphlen + grelen + gre->hasSeq * be16dec(&gre->length));
818	if (extralen < 0) {
819		priv->stats.recvBadGRE++;
820		ERROUT(EINVAL);
821	}
822	if ((be32dec(gre) & PPTP_INIT_MASK) != PPTP_INIT_VALUE) {
823		priv->stats.recvBadGRE++;
824		ERROUT(EINVAL);
825	}
826
827	hpriv = ng_pptpgre_find_session(priv, be16dec(&gre->cid));
828	if (hpriv == NULL || hpriv->hook == NULL || !hpriv->conf.enabled) {
829		priv->stats.recvBadCID++;
830		ERROUT(EINVAL);
831	}
832	mtx_lock(&hpriv->mtx);
833
834	/* Look for peer ack */
835	if (gre->hasAck) {
836		const u_int32_t	ack = be32dec(&gre->data[gre->hasSeq]);
837		const int index = ack - hpriv->recvAck - 1;
838		long sample;
839
840		/* Sanity check ack value */
841		if (PPTP_SEQ_DIFF(ack, hpriv->xmitSeq) > 0) {
842			priv->stats.recvBadAcks++;
843			goto badAck;		/* we never sent it! */
844		}
845		if (PPTP_SEQ_DIFF(ack, hpriv->recvAck) <= 0)
846			goto badAck;		/* ack already timed out */
847		hpriv->recvAck = ack;
848
849		/* Update adaptive timeout stuff */
850		if (hpriv->conf.enableWindowing) {
851			sample = ng_pptpgre_time() - hpriv->timeSent[index];
852			diff = sample - hpriv->rtt;
853			hpriv->rtt += PPTP_ACK_ALPHA(diff);
854			if (diff < 0)
855				diff = -diff;
856			hpriv->dev += PPTP_ACK_BETA(diff - hpriv->dev);
857			    /* +2 to compensate low precision of int math */
858			hpriv->ato = hpriv->rtt + PPTP_ACK_CHI(hpriv->dev + 2);
859			if (hpriv->ato > PPTP_MAX_TIMEOUT)
860				hpriv->ato = PPTP_MAX_TIMEOUT;
861			else if (hpriv->ato < PPTP_MIN_TIMEOUT)
862				hpriv->ato = PPTP_MIN_TIMEOUT;
863
864			/* Shift packet transmit times in our transmit window */
865			bcopy(hpriv->timeSent + index + 1, hpriv->timeSent,
866			    sizeof(*hpriv->timeSent)
867			      * (PPTP_XMIT_WIN - (index + 1)));
868
869			/* If we sent an entire window, increase window size */
870			if (PPTP_SEQ_DIFF(ack, hpriv->winAck) >= 0
871			    && hpriv->xmitWin < PPTP_XMIT_WIN) {
872				hpriv->xmitWin++;
873				hpriv->winAck = ack + hpriv->xmitWin;
874			}
875
876			/* Stop/(re)start receive ACK timer as necessary */
877			ng_uncallout(&hpriv->rackTimer, hpriv->node);
878			if (hpriv->recvAck != hpriv->xmitSeq)
879				ng_pptpgre_start_recv_ack_timer(hpriv);
880		}
881	}
882badAck:
883
884	/* See if frame contains any data */
885	if (!gre->hasSeq) {		/* no data to deliver */
886		priv->stats.recvLoneAcks++;
887		mtx_unlock(&hpriv->mtx);
888		ERROUT(0);
889	}
890
891	seq = be32dec(&gre->data[0]);
892
893	diff = PPTP_SEQ_DIFF(seq, hpriv->recvSeq);
894	if (diff <= 0) {			/* late or duplicate packet */
895		if (diff < 0 && reorder_max == 0)	/* reorder disabled */
896			priv->stats.recvOutOfOrder++;	/* late */
897		else
898			priv->stats.recvDuplicates++;	/* duplicate */
899		mtx_unlock(&hpriv->mtx);
900		ERROUT(EINVAL);
901	}
902
903	/* Trim mbuf down to internal payload */
904	m_adj(m, iphlen + grelen);
905	if (extralen > 0)
906		m_adj(m, -extralen);
907
908#define INIT_SENDQ(t) do {				\
909		t.item = item;				\
910		t.seq = seq;				\
911		SLIST_INSERT_HEAD(&sendq, &t, next);	\
912		last = &t;				\
913		hpriv->recvSeq = seq;			\
914		goto deliver;				\
915	} while(0)
916
917	if (diff == 1)
918		/* the packet came in order, place it at the start of sendq */
919		INIT_SENDQ(temp);
920
921	/* The packet came too early, try to enqueue it.
922	 *
923	 * Check for duplicate in the queue. After this loop, "prev" will be
924	 * NULL if the packet should become new head of the queue,
925	 * or else it should be inserted after the "prev".
926	 */
927	prev = SLIST_FIRST(&hpriv->roq);
928	SLIST_FOREACH(np, &hpriv->roq, next) {
929		diff = PPTP_SEQ_DIFF(np->seq, seq);
930		if (diff == 0) { /* do not add duplicate, drop it */
931			priv->stats.recvDuplicates++;
932			mtx_unlock(&hpriv->mtx);
933			ERROUT(EINVAL);
934		}
935		if (diff > 0) {		/* we found newer packet */
936			if (np == prev)	/* that is the head of the queue */
937			    prev = NULL; /* put current packet to the head */
938			break;
939		}
940		prev = np;
941	}
942
943	priv->stats.recvOutOfOrder++;	/* duplicate not found */
944	if (hpriv->roq_len < reorder_max)
945		goto enqueue;	/* reorder enabled and there is a room */
946
947	/*
948	 * There is no room in the queue or reorder disabled.
949	 *
950	 * It the latter case, we may still have non-empty reorder queue
951	 * if reorder was disabled in process of reordering.
952	 * Then we correctly deliver the queue without growing it.
953	 *
954	 * In both cases, no malloc()'s until the queue is shortened.
955	 */
956	priv->stats.recvReorderOverflow++;
957	if (prev == NULL) {	  /* new packet goes before the head      */
958		INIT_SENDQ(temp); /* of reorder queue, so put it to sendq */
959	}
960#undef INIT_SENDQ
961
962	/*
963	 * Current packet goes after the head of reorder queue.
964	 * Move the head to sendq to make room for current packet.
965	 */
966	np = SLIST_FIRST(&hpriv->roq);
967	if (prev == np)
968		prev = NULL;
969	SLIST_REMOVE_HEAD(&hpriv->roq, next);
970	hpriv->roq_len--;	/* we are allowed to use malloc() now */
971	SLIST_INSERT_HEAD(&sendq, np, next);
972	last = np;
973	hpriv->recvSeq = np->seq;
974
975enqueue:
976	np = malloc(sizeof(*np), M_NETGRAPH_PPTP, M_NOWAIT | M_ZERO);
977	if (np == NULL) {
978		priv->stats.memoryFailures++;
979		/*
980		 * Emergency: we cannot save new data.
981		 * Flush the queue delivering all queued packets preceeding
982		 * current one despite of gaps.
983		 */
984		while (!SLIST_EMPTY(&hpriv->roq)) {
985			np = SLIST_FIRST(&hpriv->roq);
986			if (np->seq > seq)
987				break;
988			SLIST_REMOVE_HEAD(&hpriv->roq, next);
989			hpriv->roq_len--;
990			if (last == NULL)
991				SLIST_INSERT_HEAD(&sendq, np, next);
992			else
993				SLIST_INSERT_AFTER(last, np, next);
994			last = np;
995		}
996
997		/*
998		 * Pretend we got all packets till the current one
999		 * and acknowledge it.
1000		 */
1001		hpriv->recvSeq = seq;
1002		ng_pptpgre_ack(hpriv);	/* drops lock */
1003		ng_pptpgre_sendq(hpriv, &sendq, &temp);
1004		NG_FWD_NEW_DATA(error, item, hpriv->hook, m);
1005		ERROUT(ENOMEM);
1006	}
1007
1008	/* Add current (early) packet to the reorder queue. */
1009	np->item = item;
1010	np->seq = seq;
1011	if (prev == NULL)
1012		SLIST_INSERT_HEAD(&hpriv->roq, np, next);
1013	else
1014		SLIST_INSERT_AFTER(prev, np, next);
1015	hpriv->roq_len++;
1016
1017deliver:
1018	/* Look if we have some packets in sequence after sendq. */
1019	while (!SLIST_EMPTY(&hpriv->roq)) {
1020		np = SLIST_FIRST(&hpriv->roq);
1021		if (PPTP_SEQ_DIFF(np->seq, hpriv->recvSeq) > 1)
1022			break; /* the gap in the sequence */
1023
1024		/* "np" is in sequence, move it to the sendq. */
1025		SLIST_REMOVE_HEAD(&hpriv->roq, next);
1026		hpriv->roq_len--;
1027		hpriv->recvSeq = np->seq;
1028
1029		if (last == NULL)
1030			SLIST_INSERT_HEAD(&sendq, np, next);
1031		else
1032			SLIST_INSERT_AFTER(last, np, next);
1033		last = np;
1034	}
1035
1036	if (SLIST_EMPTY(&hpriv->roq)) {
1037		if (callout_pending(&hpriv->reorderTimer))
1038			ng_uncallout(&hpriv->reorderTimer, hpriv->node);
1039	} else {
1040		if (!callout_pending(&hpriv->reorderTimer))
1041			ng_pptpgre_start_reorder_timer(hpriv);
1042	}
1043
1044	if (SLIST_EMPTY(&sendq)) {
1045		/* Current packet has been queued, nothing to free/deliver. */
1046		mtx_unlock(&hpriv->mtx);
1047		return (error);
1048	}
1049
1050	/* We need to acknowledge last packet; do it soon... */
1051	ng_pptpgre_ack(hpriv);		/* drops lock */
1052	ng_pptpgre_sendq(hpriv, &sendq, &temp);
1053	return (error);
1054
1055done:
1056	NG_FREE_ITEM(item);
1057	return (error);
1058}
1059
1060/*************************************************************************
1061		    TIMER RELATED FUNCTIONS
1062*************************************************************************/
1063
1064/*
1065 * Start a timer for the peer's acknowledging our oldest unacknowledged
1066 * sequence number.  If we get an ack for this sequence number before
1067 * the timer goes off, we cancel the timer.  Resets currently running
1068 * recv ack timer, if any.
1069 */
1070static void
1071ng_pptpgre_start_recv_ack_timer(hpriv_p hpriv)
1072{
1073	int remain, ticks;
1074
1075	/* Compute how long until oldest unack'd packet times out,
1076	   and reset the timer to that time. */
1077	remain = (hpriv->timeSent[0] + hpriv->ato) - ng_pptpgre_time();
1078	if (remain < 0)
1079		remain = 0;
1080
1081	/* Be conservative: timeout can happen up to 1 tick early */
1082	ticks = howmany(remain * hz, PPTP_TIME_SCALE) + 1;
1083	ng_callout(&hpriv->rackTimer, hpriv->node, hpriv->hook,
1084	    ticks, ng_pptpgre_recv_ack_timeout, hpriv, 0);
1085}
1086
1087/*
1088 * The peer has failed to acknowledge the oldest unacknowledged sequence
1089 * number within the time allotted.  Update our adaptive timeout parameters
1090 * and reset/restart the recv ack timer.
1091 */
1092static void
1093ng_pptpgre_recv_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2)
1094{
1095	const priv_p priv = NG_NODE_PRIVATE(node);
1096	const hpriv_p hpriv = arg1;
1097
1098	/* Update adaptive timeout stuff */
1099	priv->stats.recvAckTimeouts++;
1100	hpriv->rtt = PPTP_ACK_DELTA(hpriv->rtt) + 1; /* +1 to avoid delta*0 case */
1101	hpriv->ato = hpriv->rtt + PPTP_ACK_CHI(hpriv->dev);
1102	if (hpriv->ato > PPTP_MAX_TIMEOUT)
1103		hpriv->ato = PPTP_MAX_TIMEOUT;
1104	else if (hpriv->ato < PPTP_MIN_TIMEOUT)
1105		hpriv->ato = PPTP_MIN_TIMEOUT;
1106
1107	/* Reset ack and sliding window */
1108	hpriv->recvAck = hpriv->xmitSeq;		/* pretend we got the ack */
1109	hpriv->xmitWin = (hpriv->xmitWin + 1) / 2;	/* shrink transmit window */
1110	hpriv->winAck = hpriv->recvAck + hpriv->xmitWin;	/* reset win expand time */
1111}
1112
1113/*
1114 * Start the send ack timer. This assumes the timer is not
1115 * already running.
1116 */
1117static void
1118ng_pptpgre_start_send_ack_timer(hpriv_p hpriv)
1119{
1120	int ackTimeout, ticks;
1121
1122	/* Take 1/4 of the estimated round trip time */
1123	ackTimeout = (hpriv->rtt >> 2);
1124	if (ackTimeout < PPTP_MIN_ACK_DELAY)
1125		ackTimeout = PPTP_MIN_ACK_DELAY;
1126	else if (ackTimeout > PPTP_MAX_ACK_DELAY)
1127		ackTimeout = PPTP_MAX_ACK_DELAY;
1128
1129	/* Be conservative: timeout can happen up to 1 tick early */
1130	ticks = howmany(ackTimeout * hz, PPTP_TIME_SCALE);
1131	ng_callout(&hpriv->sackTimer, hpriv->node, hpriv->hook,
1132	    ticks, ng_pptpgre_send_ack_timeout, hpriv, 0);
1133}
1134
1135/*
1136 * We've waited as long as we're willing to wait before sending an
1137 * acknowledgement to the peer for received frames. We had hoped to
1138 * be able to piggy back our acknowledgement on an outgoing data frame,
1139 * but apparently there haven't been any since. So send the ack now.
1140 */
1141static void
1142ng_pptpgre_send_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2)
1143{
1144	const hpriv_p hpriv = arg1;
1145
1146	mtx_lock(&hpriv->mtx);
1147	/* Send a frame with an ack but no payload */
1148  	ng_pptpgre_xmit(hpriv, NULL);
1149	mtx_assert(&hpriv->mtx, MA_NOTOWNED);
1150}
1151
1152/*
1153 * Start a timer for the reorder queue. This assumes the timer is not
1154 * already running.
1155 */
1156static void
1157ng_pptpgre_start_reorder_timer(hpriv_p hpriv)
1158{
1159	int ticks;
1160
1161	/* Be conservative: timeout can happen up to 1 tick early */
1162	ticks = (((reorder_timeout * hz) + 1000 - 1) / 1000) + 1;
1163	ng_callout(&hpriv->reorderTimer, hpriv->node, hpriv->hook,
1164		ticks, ng_pptpgre_reorder_timeout, hpriv, 0);
1165}
1166
1167/*
1168 * The oldest packet spent too much time in the reorder queue.
1169 * Deliver it and next packets in sequence, if any.
1170 */
1171static void
1172ng_pptpgre_reorder_timeout(node_p node, hook_p hook, void *arg1, int arg2)
1173{
1174	const priv_p priv = NG_NODE_PRIVATE(node);
1175	const hpriv_p hpriv = arg1;
1176	roqh sendq = SLIST_HEAD_INITIALIZER(sendq);
1177	struct ng_pptpgre_roq *np, *last = NULL;
1178
1179	priv->stats.recvReorderTimeouts++;
1180	mtx_lock(&hpriv->mtx);
1181	if (SLIST_EMPTY(&hpriv->roq)) { /* should not happen */
1182		mtx_unlock(&hpriv->mtx);
1183		return;
1184	}
1185
1186	last = np = SLIST_FIRST(&hpriv->roq);
1187	hpriv->roq_len--;
1188	SLIST_REMOVE_HEAD(&hpriv->roq, next);
1189	SLIST_INSERT_HEAD(&sendq, np, next);
1190
1191	/* Look if we have more packets in sequence */
1192	while (!SLIST_EMPTY(&hpriv->roq)) {
1193		np = SLIST_FIRST(&hpriv->roq);
1194		if (PPTP_SEQ_DIFF(np->seq, last->seq) > 1)
1195			break; /* the gap in the sequence */
1196
1197		/* Next packet is in sequence, move it to the sendq. */
1198		hpriv->roq_len--;
1199		SLIST_REMOVE_HEAD(&hpriv->roq, next);
1200		SLIST_INSERT_AFTER(last, np, next);
1201		last = np;
1202	}
1203
1204	hpriv->recvSeq = last->seq;
1205	if (!SLIST_EMPTY(&hpriv->roq))
1206		ng_pptpgre_start_reorder_timer(hpriv);
1207
1208	/* We need to acknowledge last packet; do it soon... */
1209	ng_pptpgre_ack(hpriv);		/* drops lock */
1210	ng_pptpgre_sendq(hpriv, &sendq, NULL);
1211	mtx_assert(&hpriv->mtx, MA_NOTOWNED);
1212}
1213
1214/*************************************************************************
1215		    MISC FUNCTIONS
1216*************************************************************************/
1217
1218/*
1219 * Find the hook with a given session ID.
1220 */
1221static hpriv_p
1222ng_pptpgre_find_session(priv_p privp, u_int16_t cid)
1223{
1224	uint16_t	hash = SESSHASH(cid);
1225	hpriv_p	hpriv = NULL;
1226
1227	LIST_FOREACH(hpriv, &privp->sesshash[hash], sessions) {
1228		if (hpriv->conf.cid == cid)
1229			break;
1230	}
1231
1232	return (hpriv);
1233}
1234
1235/*
1236 * Reset state (must be called with lock held or from writer)
1237 */
1238static void
1239ng_pptpgre_reset(hpriv_p hpriv)
1240{
1241	struct ng_pptpgre_roq *np;
1242
1243	/* Reset adaptive timeout state */
1244	hpriv->ato = PPTP_MAX_TIMEOUT;
1245	hpriv->rtt = PPTP_TIME_SCALE / 10;
1246	if (hpriv->conf.peerPpd > 1)	/* ppd = 0 treat as = 1 */
1247		hpriv->rtt *= hpriv->conf.peerPpd;
1248	hpriv->dev = 0;
1249	hpriv->xmitWin = (hpriv->conf.recvWin + 1) / 2;
1250	if (hpriv->xmitWin < 2)		/* often the first packet is lost */
1251		hpriv->xmitWin = 2;		/*   because the peer isn't ready */
1252	else if (hpriv->xmitWin > PPTP_XMIT_WIN)
1253		hpriv->xmitWin = PPTP_XMIT_WIN;
1254	hpriv->winAck = hpriv->xmitWin;
1255
1256	/* Reset sequence numbers */
1257	hpriv->recvSeq = ~0;
1258	hpriv->recvAck = ~0;
1259	hpriv->xmitSeq = ~0;
1260	hpriv->xmitAck = ~0;
1261
1262	/* Stop timers */
1263	ng_uncallout(&hpriv->sackTimer, hpriv->node);
1264	ng_uncallout(&hpriv->rackTimer, hpriv->node);
1265	ng_uncallout(&hpriv->reorderTimer, hpriv->node);
1266
1267	/* Clear reorder queue */
1268	while (!SLIST_EMPTY(&hpriv->roq)) {
1269		np = SLIST_FIRST(&hpriv->roq);
1270		SLIST_REMOVE_HEAD(&hpriv->roq, next);
1271		NG_FREE_ITEM(np->item);
1272		free(np, M_NETGRAPH_PPTP);
1273	}
1274	hpriv->roq_len = 0;
1275}
1276
1277/*
1278 * Return the current time scaled & translated to our internally used format.
1279 */
1280static pptptime_t
1281ng_pptpgre_time(void)
1282{
1283	struct timeval tv;
1284	pptptime_t t;
1285
1286	microuptime(&tv);
1287	t = (pptptime_t)tv.tv_sec * PPTP_TIME_SCALE;
1288	t += tv.tv_usec / (1000000 / PPTP_TIME_SCALE);
1289	return(t);
1290}
1291