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