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, 0, "PPTPGRE");
149
150/*
151 * Reorder queue maximum length. Zero disables reorder.
152 *
153 * The node may keep reorder_max queue entries per session
154 * if reorder is enabled, plus allocate one more for short time.
155 *
156 * Be conservative in memory consumption by default.
157 * Lots of sessions with large queues can overflow M_NETGRAPH zone.
158 */
159static int reorder_max = 1; /* reorder up to two swapped packets in a row */
160SYSCTL_UINT(_net_graph_pptpgre, OID_AUTO, reorder_max, CTLFLAG_RWTUN,
161	&reorder_max, 0, "Reorder queue maximum length");
162
163static int reorder_timeout = PPTP_REORDER_TIMEOUT;
164SYSCTL_UINT(_net_graph_pptpgre, OID_AUTO, reorder_timeout, CTLFLAG_RWTUN,
165	&reorder_timeout, 0, "Reorder timeout is milliseconds");
166
167/* Packet reorder FIFO queue */
168struct ng_pptpgre_roq {
169	SLIST_ENTRY(ng_pptpgre_roq)  next;	/* next entry of the queue */
170	item_p			item;		/* netgraph item */
171	u_int32_t		seq;		/* packet sequence number */
172};
173SLIST_HEAD(ng_pptpgre_roq_head, ng_pptpgre_roq);
174typedef struct ng_pptpgre_roq_head roqh;
175
176/* We keep packet retransmit and acknowlegement state in this struct */
177struct ng_pptpgre_sess {
178	node_p			node;		/* this node pointer */
179	hook_p			hook;		/* hook to upper layers */
180	struct ng_pptpgre_conf	conf;		/* configuration info */
181	struct mtx		mtx;		/* session mutex */
182	u_int32_t		recvSeq;	/* last seq # we rcv'd */
183	u_int32_t		xmitSeq;	/* last seq # we sent */
184	u_int32_t		recvAck;	/* last seq # peer ack'd */
185	u_int32_t		xmitAck;	/* last seq # we ack'd */
186	int32_t			ato;		/* adaptive time-out value */
187	int32_t			rtt;		/* round trip time estimate */
188	int32_t			dev;		/* deviation estimate */
189	u_int16_t		xmitWin;	/* size of xmit window */
190	struct callout		sackTimer;	/* send ack timer */
191	struct callout		rackTimer;	/* recv ack timer */
192	u_int32_t		winAck;		/* seq when xmitWin will grow */
193	pptptime_t		timeSent[PPTP_XMIT_WIN];
194	LIST_ENTRY(ng_pptpgre_sess) sessions;
195	roqh			roq;		/* reorder queue head */
196	u_int8_t		roq_len;	/* reorder queue length */
197	struct callout		reorderTimer;	/* reorder timeout handler */
198};
199typedef struct ng_pptpgre_sess *hpriv_p;
200
201/* Node private data */
202struct ng_pptpgre_private {
203	hook_p			upper;		/* hook to upper layers */
204	hook_p			lower;		/* hook to lower layers */
205	struct ng_pptpgre_sess	uppersess;	/* default session for compat */
206	LIST_HEAD(, ng_pptpgre_sess) sesshash[SESSHASHSIZE];
207	struct ng_pptpgre_stats	stats;		/* node statistics */
208};
209typedef struct ng_pptpgre_private *priv_p;
210
211/* Netgraph node methods */
212static ng_constructor_t	ng_pptpgre_constructor;
213static ng_rcvmsg_t	ng_pptpgre_rcvmsg;
214static ng_shutdown_t	ng_pptpgre_shutdown;
215static ng_newhook_t	ng_pptpgre_newhook;
216static ng_rcvdata_t	ng_pptpgre_rcvdata;
217static ng_rcvdata_t	ng_pptpgre_rcvdata_lower;
218static ng_disconnect_t	ng_pptpgre_disconnect;
219
220/* Helper functions */
221static int	ng_pptpgre_xmit(hpriv_p hpriv, item_p item);
222static void	ng_pptpgre_start_send_ack_timer(hpriv_p hpriv);
223static void	ng_pptpgre_start_recv_ack_timer(hpriv_p hpriv);
224static void	ng_pptpgre_start_reorder_timer(hpriv_p hpriv);
225static void	ng_pptpgre_recv_ack_timeout(node_p node, hook_p hook,
226		    void *arg1, int arg2);
227static void	ng_pptpgre_send_ack_timeout(node_p node, hook_p hook,
228		    void *arg1, int arg2);
229static void	ng_pptpgre_reorder_timeout(node_p node, hook_p hook,
230		    void *arg1, int arg2);
231static hpriv_p	ng_pptpgre_find_session(priv_p privp, u_int16_t cid);
232static void	ng_pptpgre_reset(hpriv_p hpriv);
233static pptptime_t ng_pptpgre_time(void);
234static void	ng_pptpgre_ack(const hpriv_p hpriv);
235static int	ng_pptpgre_sendq(const hpriv_p hpriv, roqh *q,
236		    const struct ng_pptpgre_roq *st);
237
238/* Parse type for struct ng_pptpgre_conf */
239static const struct ng_parse_struct_field ng_pptpgre_conf_type_fields[]
240	= NG_PPTPGRE_CONF_TYPE_INFO;
241static const struct ng_parse_type ng_pptpgre_conf_type = {
242	&ng_parse_struct_type,
243	&ng_pptpgre_conf_type_fields,
244};
245
246/* Parse type for struct ng_pptpgre_stats */
247static const struct ng_parse_struct_field ng_pptpgre_stats_type_fields[]
248	= NG_PPTPGRE_STATS_TYPE_INFO;
249static const struct ng_parse_type ng_pptp_stats_type = {
250	&ng_parse_struct_type,
251	&ng_pptpgre_stats_type_fields
252};
253
254/* List of commands and how to convert arguments to/from ASCII */
255static const struct ng_cmdlist ng_pptpgre_cmdlist[] = {
256	{
257	  NGM_PPTPGRE_COOKIE,
258	  NGM_PPTPGRE_SET_CONFIG,
259	  "setconfig",
260	  &ng_pptpgre_conf_type,
261	  NULL
262	},
263	{
264	  NGM_PPTPGRE_COOKIE,
265	  NGM_PPTPGRE_GET_CONFIG,
266	  "getconfig",
267	  &ng_parse_hint16_type,
268	  &ng_pptpgre_conf_type
269	},
270	{
271	  NGM_PPTPGRE_COOKIE,
272	  NGM_PPTPGRE_GET_STATS,
273	  "getstats",
274	  NULL,
275	  &ng_pptp_stats_type
276	},
277	{
278	  NGM_PPTPGRE_COOKIE,
279	  NGM_PPTPGRE_CLR_STATS,
280	  "clrstats",
281	  NULL,
282	  NULL
283	},
284	{
285	  NGM_PPTPGRE_COOKIE,
286	  NGM_PPTPGRE_GETCLR_STATS,
287	  "getclrstats",
288	  NULL,
289	  &ng_pptp_stats_type
290	},
291	{ 0 }
292};
293
294/* Node type descriptor */
295static struct ng_type ng_pptpgre_typestruct = {
296	.version =	NG_ABI_VERSION,
297	.name =		NG_PPTPGRE_NODE_TYPE,
298	.constructor =	ng_pptpgre_constructor,
299	.rcvmsg =	ng_pptpgre_rcvmsg,
300	.shutdown =	ng_pptpgre_shutdown,
301	.newhook =	ng_pptpgre_newhook,
302	.rcvdata =	ng_pptpgre_rcvdata,
303	.disconnect =	ng_pptpgre_disconnect,
304	.cmdlist =	ng_pptpgre_cmdlist,
305};
306NETGRAPH_INIT(pptpgre, &ng_pptpgre_typestruct);
307
308#define ERROUT(x)	do { error = (x); goto done; } while (0)
309
310/************************************************************************
311			NETGRAPH NODE STUFF
312 ************************************************************************/
313
314/*
315 * Node type constructor
316 */
317static int
318ng_pptpgre_constructor(node_p node)
319{
320	priv_p priv;
321	int i;
322
323	/* Allocate private structure */
324	priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO);
325
326	NG_NODE_SET_PRIVATE(node, priv);
327
328	/* Initialize state */
329	mtx_init(&priv->uppersess.mtx, "ng_pptp", NULL, MTX_DEF);
330	ng_callout_init(&priv->uppersess.sackTimer);
331	ng_callout_init(&priv->uppersess.rackTimer);
332	priv->uppersess.node = node;
333
334	SLIST_INIT(&priv->uppersess.roq);
335	priv->uppersess.roq_len = 0;
336	ng_callout_init(&priv->uppersess.reorderTimer);
337
338	for (i = 0; i < SESSHASHSIZE; i++)
339	    LIST_INIT(&priv->sesshash[i]);
340
341	LIST_INSERT_HEAD(&priv->sesshash[0], &priv->uppersess, sessions);
342
343	/* Done */
344	return (0);
345}
346
347/*
348 * Give our OK for a hook to be added.
349 */
350static int
351ng_pptpgre_newhook(node_p node, hook_p hook, const char *name)
352{
353	const priv_p priv = NG_NODE_PRIVATE(node);
354
355	/* Check hook name */
356	if (strcmp(name, NG_PPTPGRE_HOOK_UPPER) == 0) {
357		priv->upper = hook;
358		priv->uppersess.hook = hook;
359		NG_HOOK_SET_PRIVATE(hook, &priv->uppersess);
360	} else if (strcmp(name, NG_PPTPGRE_HOOK_LOWER) == 0) {
361		priv->lower = hook;
362		NG_HOOK_SET_RCVDATA(hook, ng_pptpgre_rcvdata_lower);
363	} else {
364		static const char hexdig[16] = "0123456789abcdef";
365		const char *hex;
366		hpriv_p hpriv;
367		int i, j;
368		uint16_t cid, hash;
369
370		/* Parse hook name to get session ID */
371		if (strncmp(name, NG_PPTPGRE_HOOK_SESSION_P,
372		    sizeof(NG_PPTPGRE_HOOK_SESSION_P) - 1) != 0)
373			return (EINVAL);
374		hex = name + sizeof(NG_PPTPGRE_HOOK_SESSION_P) - 1;
375		for (cid = i = 0; i < 4; i++) {
376			for (j = 0; j < 16 && hex[i] != hexdig[j]; j++);
377			if (j == 16)
378				return (EINVAL);
379			cid = (cid << 4) | j;
380		}
381		if (hex[i] != '\0')
382			return (EINVAL);
383
384		hpriv = malloc(sizeof(*hpriv), M_NETGRAPH, M_NOWAIT | M_ZERO);
385		if (hpriv == NULL)
386			return (ENOMEM);
387
388		/* Initialize state */
389		mtx_init(&hpriv->mtx, "ng_pptp", NULL, MTX_DEF);
390		ng_callout_init(&hpriv->sackTimer);
391		ng_callout_init(&hpriv->rackTimer);
392		hpriv->conf.cid = cid;
393		hpriv->node = node;
394		hpriv->hook = hook;
395
396		SLIST_INIT(&hpriv->roq);
397		hpriv->roq_len = 0;
398		ng_callout_init(&hpriv->reorderTimer);
399
400		NG_HOOK_SET_PRIVATE(hook, hpriv);
401
402		hash = SESSHASH(cid);
403		LIST_INSERT_HEAD(&priv->sesshash[hash], hpriv, sessions);
404	}
405
406	return (0);
407}
408
409/*
410 * Receive a control message.
411 */
412static int
413ng_pptpgre_rcvmsg(node_p node, item_p item, hook_p lasthook)
414{
415	const priv_p priv = NG_NODE_PRIVATE(node);
416	struct ng_mesg *resp = NULL;
417	int error = 0;
418	struct ng_mesg *msg;
419
420	NGI_GET_MSG(item, msg);
421	switch (msg->header.typecookie) {
422	case NGM_PPTPGRE_COOKIE:
423		switch (msg->header.cmd) {
424		case NGM_PPTPGRE_SET_CONFIG:
425		    {
426			struct ng_pptpgre_conf *const newConf =
427				(struct ng_pptpgre_conf *) msg->data;
428			hpriv_p hpriv;
429			uint16_t hash;
430
431			/* Check for invalid or illegal config */
432			if (msg->header.arglen != sizeof(*newConf))
433				ERROUT(EINVAL);
434			/* Try to find session by cid. */
435			hpriv = ng_pptpgre_find_session(priv, newConf->cid);
436			/* If not present - use upper. */
437			if (hpriv == NULL) {
438				hpriv = &priv->uppersess;
439				LIST_REMOVE(hpriv, sessions);
440				hash = SESSHASH(newConf->cid);
441				LIST_INSERT_HEAD(&priv->sesshash[hash], hpriv,
442				    sessions);
443			}
444			ng_pptpgre_reset(hpriv);	/* reset on configure */
445			hpriv->conf = *newConf;
446			break;
447		    }
448		case NGM_PPTPGRE_GET_CONFIG:
449		    {
450			hpriv_p hpriv;
451
452			if (msg->header.arglen == 2) {
453				/* Try to find session by cid. */
454	    			hpriv = ng_pptpgre_find_session(priv,
455				    *((uint16_t *)msg->data));
456				if (hpriv == NULL)
457					ERROUT(EINVAL);
458			} else if (msg->header.arglen == 0) {
459				/* Use upper. */
460				hpriv = &priv->uppersess;
461			} else
462				ERROUT(EINVAL);
463			NG_MKRESPONSE(resp, msg, sizeof(hpriv->conf), M_NOWAIT);
464			if (resp == NULL)
465				ERROUT(ENOMEM);
466			bcopy(&hpriv->conf, resp->data, sizeof(hpriv->conf));
467			break;
468		    }
469		case NGM_PPTPGRE_GET_STATS:
470		case NGM_PPTPGRE_CLR_STATS:
471		case NGM_PPTPGRE_GETCLR_STATS:
472		    {
473			if (msg->header.cmd != NGM_PPTPGRE_CLR_STATS) {
474				NG_MKRESPONSE(resp, msg,
475				    sizeof(priv->stats), M_NOWAIT);
476				if (resp == NULL)
477					ERROUT(ENOMEM);
478				bcopy(&priv->stats,
479				    resp->data, sizeof(priv->stats));
480			}
481			if (msg->header.cmd != NGM_PPTPGRE_GET_STATS)
482				bzero(&priv->stats, sizeof(priv->stats));
483			break;
484		    }
485		default:
486			error = EINVAL;
487			break;
488		}
489		break;
490	default:
491		error = EINVAL;
492		break;
493	}
494done:
495	NG_RESPOND_MSG(error, node, item, resp);
496	NG_FREE_MSG(msg);
497	return (error);
498}
499
500/*
501 * Receive incoming data on a hook.
502 */
503static int
504ng_pptpgre_rcvdata(hook_p hook, item_p item)
505{
506	const hpriv_p hpriv = NG_HOOK_PRIVATE(hook);
507	int rval;
508
509	/* If not configured, reject */
510	if (!hpriv->conf.enabled) {
511		NG_FREE_ITEM(item);
512		return (ENXIO);
513	}
514
515	mtx_lock(&hpriv->mtx);
516
517	rval = ng_pptpgre_xmit(hpriv, item);
518
519	mtx_assert(&hpriv->mtx, MA_NOTOWNED);
520
521	return (rval);
522}
523
524/*
525 * Hook disconnection
526 */
527static int
528ng_pptpgre_disconnect(hook_p hook)
529{
530	const node_p node = NG_HOOK_NODE(hook);
531	const priv_p priv = NG_NODE_PRIVATE(node);
532	const hpriv_p hpriv = NG_HOOK_PRIVATE(hook);
533
534	/* Zero out hook pointer */
535	if (hook == priv->upper) {
536		priv->upper = NULL;
537		priv->uppersess.hook = NULL;
538	} else if (hook == priv->lower) {
539		priv->lower = NULL;
540	} else {
541		/* Reset node (stops timers) */
542		ng_pptpgre_reset(hpriv);
543
544		LIST_REMOVE(hpriv, sessions);
545		mtx_destroy(&hpriv->mtx);
546		free(hpriv, M_NETGRAPH);
547	}
548
549	/* Go away if no longer connected to anything */
550	if ((NG_NODE_NUMHOOKS(node) == 0)
551	&& (NG_NODE_IS_VALID(node)))
552		ng_rmnode_self(node);
553	return (0);
554}
555
556/*
557 * Destroy node
558 */
559static int
560ng_pptpgre_shutdown(node_p node)
561{
562	const priv_p priv = NG_NODE_PRIVATE(node);
563
564	/* Reset node (stops timers) */
565	ng_pptpgre_reset(&priv->uppersess);
566
567	LIST_REMOVE(&priv->uppersess, sessions);
568	mtx_destroy(&priv->uppersess.mtx);
569
570	free(priv, M_NETGRAPH);
571
572	/* Decrement ref count */
573	NG_NODE_UNREF(node);
574	return (0);
575}
576
577/*************************************************************************
578		    TRANSMIT AND RECEIVE FUNCTIONS
579*************************************************************************/
580
581/*
582 * Transmit an outgoing frame, or just an ack if m is NULL.
583 */
584static int
585ng_pptpgre_xmit(hpriv_p hpriv, item_p item)
586{
587	const priv_p priv = NG_NODE_PRIVATE(hpriv->node);
588	u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)];
589	struct greheader *const gre = (struct greheader *)buf;
590	int grelen, error;
591	struct mbuf *m;
592
593	mtx_assert(&hpriv->mtx, MA_OWNED);
594
595	if (item) {
596		NGI_GET_M(item, m);
597	} else {
598		m = NULL;
599	}
600	/* Check if there's data */
601	if (m != NULL) {
602
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