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
68#include <netinet/in.h>
69#include <netinet/in_systm.h>
70#include <netinet/ip.h>
71
72#include <netgraph/ng_message.h>
73#include <netgraph/netgraph.h>
74#include <netgraph/ng_parse.h>
75#include <netgraph/ng_pptpgre.h>
76
77/* GRE packet format, as used by PPTP */
78struct greheader {
79#if BYTE_ORDER == LITTLE_ENDIAN
80	u_char		recursion:3;		/* recursion control */
81	u_char		ssr:1;			/* strict source route */
82	u_char		hasSeq:1;		/* sequence number present */
83	u_char		hasKey:1;		/* key present */
84	u_char		hasRoute:1;		/* routing present */
85	u_char		hasSum:1;		/* checksum present */
86	u_char		vers:3;			/* version */
87	u_char		flags:4;		/* flags */
88	u_char		hasAck:1;		/* acknowlege number present */
89#elif BYTE_ORDER == BIG_ENDIAN
90	u_char		hasSum:1;		/* checksum present */
91	u_char		hasRoute:1;		/* routing present */
92	u_char		hasKey:1;		/* key present */
93	u_char		hasSeq:1;		/* sequence number present */
94	u_char		ssr:1;			/* strict source route */
95	u_char		recursion:3;		/* recursion control */
96	u_char		hasAck:1;		/* acknowlege number present */
97	u_char		flags:4;		/* flags */
98	u_char		vers:3;			/* version */
99#else
100#error BYTE_ORDER is not defined properly
101#endif
102	u_int16_t	proto;			/* protocol (ethertype) */
103	u_int16_t	length;			/* payload length */
104	u_int16_t	cid;			/* call id */
105	u_int32_t	data[0];		/* opt. seq, ack, then data */
106};
107
108/* The PPTP protocol ID used in the GRE 'proto' field */
109#define PPTP_GRE_PROTO		0x880b
110
111/* Bits that must be set a certain way in all PPTP/GRE packets */
112#define PPTP_INIT_VALUE		((0x2001 << 16) | PPTP_GRE_PROTO)
113#define PPTP_INIT_MASK		0xef7fffff
114
115/* Min and max packet length */
116#define PPTP_MAX_PAYLOAD	(0xffff - sizeof(struct greheader) - 8)
117
118/* All times are scaled by this (PPTP_TIME_SCALE time units = 1 sec.) */
119#define PPTP_TIME_SCALE		1024			/* milliseconds */
120typedef u_int64_t		pptptime_t;
121
122/* Acknowledgment timeout parameters and functions */
123#define PPTP_XMIT_WIN		16			/* max xmit window */
124#define PPTP_MIN_TIMEOUT	(PPTP_TIME_SCALE / 83)	/* 12 milliseconds */
125#define PPTP_MAX_TIMEOUT	(3 * PPTP_TIME_SCALE)	/* 3 seconds */
126
127/* When we recieve a packet, we wait to see if there's an outgoing packet
128   we can piggy-back the ACK off of. These parameters determine the mimimum
129   and maxmimum length of time we're willing to wait in order to do that.
130   These have no effect unless "enableDelayedAck" is turned on. */
131#define PPTP_MIN_ACK_DELAY	(PPTP_TIME_SCALE / 500)	/* 2 milliseconds */
132#define PPTP_MAX_ACK_DELAY	(PPTP_TIME_SCALE / 2)	/* 500 milliseconds */
133
134/* See RFC 2637 section 4.4 */
135#define PPTP_ACK_ALPHA(x)	(((x) + 4) >> 3)	/* alpha = 0.125 */
136#define PPTP_ACK_BETA(x)	(((x) + 2) >> 2)	/* beta = 0.25 */
137#define PPTP_ACK_CHI(x) 	((x) << 2)	/* chi = 4 */
138#define PPTP_ACK_DELTA(x) 	((x) << 1)	/* delta = 2 */
139
140#define PPTP_SEQ_DIFF(x,y)	((int32_t)(x) - (int32_t)(y))
141
142#define SESSHASHSIZE		0x0020
143#define SESSHASH(x)		(((x) ^ ((x) >> 8)) & (SESSHASHSIZE - 1))
144
145/* We keep packet retransmit and acknowlegement state in this struct */
146struct ng_pptpgre_sess {
147	node_p			node;		/* this node pointer */
148	hook_p			hook;		/* hook to upper layers */
149	struct ng_pptpgre_conf	conf;		/* configuration info */
150	struct mtx		mtx;		/* session mutex */
151	u_int32_t		recvSeq;	/* last seq # we rcv'd */
152	u_int32_t		xmitSeq;	/* last seq # we sent */
153	u_int32_t		recvAck;	/* last seq # peer ack'd */
154	u_int32_t		xmitAck;	/* last seq # we ack'd */
155	int32_t			ato;		/* adaptive time-out value */
156	int32_t			rtt;		/* round trip time estimate */
157	int32_t			dev;		/* deviation estimate */
158	u_int16_t		xmitWin;	/* size of xmit window */
159	struct callout		sackTimer;	/* send ack timer */
160	struct callout		rackTimer;	/* recv ack timer */
161	u_int32_t		winAck;		/* seq when xmitWin will grow */
162	pptptime_t		timeSent[PPTP_XMIT_WIN];
163	LIST_ENTRY(ng_pptpgre_sess) sessions;
164};
165typedef struct ng_pptpgre_sess *hpriv_p;
166
167/* Node private data */
168struct ng_pptpgre_private {
169	hook_p			upper;		/* hook to upper layers */
170	hook_p			lower;		/* hook to lower layers */
171	struct ng_pptpgre_sess	uppersess;	/* default session for compat */
172	LIST_HEAD(, ng_pptpgre_sess) sesshash[SESSHASHSIZE];
173	struct ng_pptpgre_stats	stats;		/* node statistics */
174};
175typedef struct ng_pptpgre_private *priv_p;
176
177/* Netgraph node methods */
178static ng_constructor_t	ng_pptpgre_constructor;
179static ng_rcvmsg_t	ng_pptpgre_rcvmsg;
180static ng_shutdown_t	ng_pptpgre_shutdown;
181static ng_newhook_t	ng_pptpgre_newhook;
182static ng_rcvdata_t	ng_pptpgre_rcvdata;
183static ng_rcvdata_t	ng_pptpgre_rcvdata_lower;
184static ng_disconnect_t	ng_pptpgre_disconnect;
185
186/* Helper functions */
187static int	ng_pptpgre_xmit(hpriv_p hpriv, item_p item);
188static void	ng_pptpgre_start_send_ack_timer(hpriv_p hpriv);
189static void	ng_pptpgre_start_recv_ack_timer(hpriv_p hpriv);
190static void	ng_pptpgre_recv_ack_timeout(node_p node, hook_p hook,
191		    void *arg1, int arg2);
192static void	ng_pptpgre_send_ack_timeout(node_p node, hook_p hook,
193		    void *arg1, int arg2);
194static hpriv_p	ng_pptpgre_find_session(priv_p privp, u_int16_t cid);
195static void	ng_pptpgre_reset(hpriv_p hpriv);
196static pptptime_t ng_pptpgre_time(void);
197
198/* Parse type for struct ng_pptpgre_conf */
199static const struct ng_parse_struct_field ng_pptpgre_conf_type_fields[]
200	= NG_PPTPGRE_CONF_TYPE_INFO;
201static const struct ng_parse_type ng_pptpgre_conf_type = {
202	&ng_parse_struct_type,
203	&ng_pptpgre_conf_type_fields,
204};
205
206/* Parse type for struct ng_pptpgre_stats */
207static const struct ng_parse_struct_field ng_pptpgre_stats_type_fields[]
208	= NG_PPTPGRE_STATS_TYPE_INFO;
209static const struct ng_parse_type ng_pptp_stats_type = {
210	&ng_parse_struct_type,
211	&ng_pptpgre_stats_type_fields
212};
213
214/* List of commands and how to convert arguments to/from ASCII */
215static const struct ng_cmdlist ng_pptpgre_cmdlist[] = {
216	{
217	  NGM_PPTPGRE_COOKIE,
218	  NGM_PPTPGRE_SET_CONFIG,
219	  "setconfig",
220	  &ng_pptpgre_conf_type,
221	  NULL
222	},
223	{
224	  NGM_PPTPGRE_COOKIE,
225	  NGM_PPTPGRE_GET_CONFIG,
226	  "getconfig",
227	  &ng_parse_hint16_type,
228	  &ng_pptpgre_conf_type
229	},
230	{
231	  NGM_PPTPGRE_COOKIE,
232	  NGM_PPTPGRE_GET_STATS,
233	  "getstats",
234	  NULL,
235	  &ng_pptp_stats_type
236	},
237	{
238	  NGM_PPTPGRE_COOKIE,
239	  NGM_PPTPGRE_CLR_STATS,
240	  "clrstats",
241	  NULL,
242	  NULL
243	},
244	{
245	  NGM_PPTPGRE_COOKIE,
246	  NGM_PPTPGRE_GETCLR_STATS,
247	  "getclrstats",
248	  NULL,
249	  &ng_pptp_stats_type
250	},
251	{ 0 }
252};
253
254/* Node type descriptor */
255static struct ng_type ng_pptpgre_typestruct = {
256	.version =	NG_ABI_VERSION,
257	.name =		NG_PPTPGRE_NODE_TYPE,
258	.constructor =	ng_pptpgre_constructor,
259	.rcvmsg =	ng_pptpgre_rcvmsg,
260	.shutdown =	ng_pptpgre_shutdown,
261	.newhook =	ng_pptpgre_newhook,
262	.rcvdata =	ng_pptpgre_rcvdata,
263	.disconnect =	ng_pptpgre_disconnect,
264	.cmdlist =	ng_pptpgre_cmdlist,
265};
266NETGRAPH_INIT(pptpgre, &ng_pptpgre_typestruct);
267
268#define ERROUT(x)	do { error = (x); goto done; } while (0)
269
270/************************************************************************
271			NETGRAPH NODE STUFF
272 ************************************************************************/
273
274/*
275 * Node type constructor
276 */
277static int
278ng_pptpgre_constructor(node_p node)
279{
280	priv_p priv;
281	int i;
282
283	/* Allocate private structure */
284	priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO);
285
286	NG_NODE_SET_PRIVATE(node, priv);
287
288	/* Initialize state */
289	mtx_init(&priv->uppersess.mtx, "ng_pptp", NULL, MTX_DEF);
290	ng_callout_init(&priv->uppersess.sackTimer);
291	ng_callout_init(&priv->uppersess.rackTimer);
292	priv->uppersess.node = node;
293
294	for (i = 0; i < SESSHASHSIZE; i++)
295	    LIST_INIT(&priv->sesshash[i]);
296
297	LIST_INSERT_HEAD(&priv->sesshash[0], &priv->uppersess, sessions);
298
299	/* Done */
300	return (0);
301}
302
303/*
304 * Give our OK for a hook to be added.
305 */
306static int
307ng_pptpgre_newhook(node_p node, hook_p hook, const char *name)
308{
309	const priv_p priv = NG_NODE_PRIVATE(node);
310
311	/* Check hook name */
312	if (strcmp(name, NG_PPTPGRE_HOOK_UPPER) == 0) {
313		priv->upper = hook;
314		priv->uppersess.hook = hook;
315		NG_HOOK_SET_PRIVATE(hook, &priv->uppersess);
316	} else if (strcmp(name, NG_PPTPGRE_HOOK_LOWER) == 0) {
317		priv->lower = hook;
318		NG_HOOK_SET_RCVDATA(hook, ng_pptpgre_rcvdata_lower);
319	} else {
320		static const char hexdig[16] = "0123456789abcdef";
321		const char *hex;
322		hpriv_p hpriv;
323		int i, j;
324		uint16_t cid, hash;
325
326		/* Parse hook name to get session ID */
327		if (strncmp(name, NG_PPTPGRE_HOOK_SESSION_P,
328		    sizeof(NG_PPTPGRE_HOOK_SESSION_P) - 1) != 0)
329			return (EINVAL);
330		hex = name + sizeof(NG_PPTPGRE_HOOK_SESSION_P) - 1;
331		for (cid = i = 0; i < 4; i++) {
332			for (j = 0; j < 16 && hex[i] != hexdig[j]; j++);
333			if (j == 16)
334				return (EINVAL);
335			cid = (cid << 4) | j;
336		}
337		if (hex[i] != '\0')
338			return (EINVAL);
339
340		hpriv = malloc(sizeof(*hpriv), M_NETGRAPH, M_NOWAIT | M_ZERO);
341		if (hpriv == NULL)
342			return (ENOMEM);
343
344		/* Initialize state */
345		mtx_init(&hpriv->mtx, "ng_pptp", NULL, MTX_DEF);
346		ng_callout_init(&hpriv->sackTimer);
347		ng_callout_init(&hpriv->rackTimer);
348		hpriv->conf.cid = cid;
349		hpriv->node = node;
350		hpriv->hook = hook;
351		NG_HOOK_SET_PRIVATE(hook, hpriv);
352
353		hash = SESSHASH(cid);
354		LIST_INSERT_HEAD(&priv->sesshash[hash], hpriv, sessions);
355	}
356
357	return (0);
358}
359
360/*
361 * Receive a control message.
362 */
363static int
364ng_pptpgre_rcvmsg(node_p node, item_p item, hook_p lasthook)
365{
366	const priv_p priv = NG_NODE_PRIVATE(node);
367	struct ng_mesg *resp = NULL;
368	int error = 0;
369	struct ng_mesg *msg;
370
371	NGI_GET_MSG(item, msg);
372	switch (msg->header.typecookie) {
373	case NGM_PPTPGRE_COOKIE:
374		switch (msg->header.cmd) {
375		case NGM_PPTPGRE_SET_CONFIG:
376		    {
377			struct ng_pptpgre_conf *const newConf =
378				(struct ng_pptpgre_conf *) msg->data;
379			hpriv_p hpriv;
380			uint16_t hash;
381
382			/* Check for invalid or illegal config */
383			if (msg->header.arglen != sizeof(*newConf))
384				ERROUT(EINVAL);
385			/* Try to find session by cid. */
386			hpriv = ng_pptpgre_find_session(priv, newConf->cid);
387			/* If not present - use upper. */
388			if (hpriv == NULL) {
389				hpriv = &priv->uppersess;
390				LIST_REMOVE(hpriv, sessions);
391				hash = SESSHASH(newConf->cid);
392				LIST_INSERT_HEAD(&priv->sesshash[hash], hpriv,
393				    sessions);
394			}
395			ng_pptpgre_reset(hpriv);	/* reset on configure */
396			hpriv->conf = *newConf;
397			break;
398		    }
399		case NGM_PPTPGRE_GET_CONFIG:
400		    {
401			hpriv_p hpriv;
402
403			if (msg->header.arglen == 2) {
404				/* Try to find session by cid. */
405	    			hpriv = ng_pptpgre_find_session(priv,
406				    *((uint16_t *)msg->data));
407				if (hpriv == NULL)
408					ERROUT(EINVAL);
409			} else if (msg->header.arglen == 0) {
410				/* Use upper. */
411				hpriv = &priv->uppersess;
412			} else
413				ERROUT(EINVAL);
414			NG_MKRESPONSE(resp, msg, sizeof(hpriv->conf), M_NOWAIT);
415			if (resp == NULL)
416				ERROUT(ENOMEM);
417			bcopy(&hpriv->conf, resp->data, sizeof(hpriv->conf));
418			break;
419		    }
420		case NGM_PPTPGRE_GET_STATS:
421		case NGM_PPTPGRE_CLR_STATS:
422		case NGM_PPTPGRE_GETCLR_STATS:
423		    {
424			if (msg->header.cmd != NGM_PPTPGRE_CLR_STATS) {
425				NG_MKRESPONSE(resp, msg,
426				    sizeof(priv->stats), M_NOWAIT);
427				if (resp == NULL)
428					ERROUT(ENOMEM);
429				bcopy(&priv->stats,
430				    resp->data, sizeof(priv->stats));
431			}
432			if (msg->header.cmd != NGM_PPTPGRE_GET_STATS)
433				bzero(&priv->stats, sizeof(priv->stats));
434			break;
435		    }
436		default:
437			error = EINVAL;
438			break;
439		}
440		break;
441	default:
442		error = EINVAL;
443		break;
444	}
445done:
446	NG_RESPOND_MSG(error, node, item, resp);
447	NG_FREE_MSG(msg);
448	return (error);
449}
450
451/*
452 * Receive incoming data on a hook.
453 */
454static int
455ng_pptpgre_rcvdata(hook_p hook, item_p item)
456{
457	const hpriv_p hpriv = NG_HOOK_PRIVATE(hook);
458	int rval;
459
460	/* If not configured, reject */
461	if (!hpriv->conf.enabled) {
462		NG_FREE_ITEM(item);
463		return (ENXIO);
464	}
465
466	mtx_lock(&hpriv->mtx);
467
468	rval = ng_pptpgre_xmit(hpriv, item);
469
470	mtx_assert(&hpriv->mtx, MA_NOTOWNED);
471
472	return (rval);
473}
474
475/*
476 * Hook disconnection
477 */
478static int
479ng_pptpgre_disconnect(hook_p hook)
480{
481	const node_p node = NG_HOOK_NODE(hook);
482	const priv_p priv = NG_NODE_PRIVATE(node);
483	const hpriv_p hpriv = NG_HOOK_PRIVATE(hook);
484
485	/* Zero out hook pointer */
486	if (hook == priv->upper) {
487		priv->upper = NULL;
488		priv->uppersess.hook = NULL;
489	} else if (hook == priv->lower) {
490		priv->lower = NULL;
491	} else {
492		/* Reset node (stops timers) */
493		ng_pptpgre_reset(hpriv);
494
495		LIST_REMOVE(hpriv, sessions);
496		mtx_destroy(&hpriv->mtx);
497		free(hpriv, M_NETGRAPH);
498	}
499
500	/* Go away if no longer connected to anything */
501	if ((NG_NODE_NUMHOOKS(node) == 0)
502	&& (NG_NODE_IS_VALID(node)))
503		ng_rmnode_self(node);
504	return (0);
505}
506
507/*
508 * Destroy node
509 */
510static int
511ng_pptpgre_shutdown(node_p node)
512{
513	const priv_p priv = NG_NODE_PRIVATE(node);
514
515	/* Reset node (stops timers) */
516	ng_pptpgre_reset(&priv->uppersess);
517
518	LIST_REMOVE(&priv->uppersess, sessions);
519	mtx_destroy(&priv->uppersess.mtx);
520
521	free(priv, M_NETGRAPH);
522
523	/* Decrement ref count */
524	NG_NODE_UNREF(node);
525	return (0);
526}
527
528/*************************************************************************
529		    TRANSMIT AND RECEIVE FUNCTIONS
530*************************************************************************/
531
532/*
533 * Transmit an outgoing frame, or just an ack if m is NULL.
534 */
535static int
536ng_pptpgre_xmit(hpriv_p hpriv, item_p item)
537{
538	const priv_p priv = NG_NODE_PRIVATE(hpriv->node);
539	u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)];
540	struct greheader *const gre = (struct greheader *)buf;
541	int grelen, error;
542	struct mbuf *m;
543
544	mtx_assert(&hpriv->mtx, MA_OWNED);
545
546	if (item) {
547		NGI_GET_M(item, m);
548	} else {
549		m = NULL;
550	}
551	/* Check if there's data */
552	if (m != NULL) {
553
554		/* Check if windowing is enabled */
555		if (hpriv->conf.enableWindowing) {
556			/* Is our transmit window full? */
557			if ((u_int32_t)PPTP_SEQ_DIFF(hpriv->xmitSeq,
558			    hpriv->recvAck) >= hpriv->xmitWin) {
559				priv->stats.xmitDrops++;
560				ERROUT(ENOBUFS);
561			}
562		}
563
564		/* Sanity check frame length */
565		if (m->m_pkthdr.len > PPTP_MAX_PAYLOAD) {
566			priv->stats.xmitTooBig++;
567			ERROUT(EMSGSIZE);
568		}
569	} else {
570		priv->stats.xmitLoneAcks++;
571	}
572
573	/* Build GRE header */
574	be32enc(gre, PPTP_INIT_VALUE);
575	be16enc(&gre->length, (m != NULL) ? m->m_pkthdr.len : 0);
576	be16enc(&gre->cid, hpriv->conf.peerCid);
577
578	/* Include sequence number if packet contains any data */
579	if (m != NULL) {
580		gre->hasSeq = 1;
581		if (hpriv->conf.enableWindowing) {
582			hpriv->timeSent[hpriv->xmitSeq - hpriv->recvAck]
583			    = ng_pptpgre_time();
584		}
585		hpriv->xmitSeq++;
586		be32enc(&gre->data[0], hpriv->xmitSeq);
587	}
588
589	/* Include acknowledgement (and stop send ack timer) if needed */
590	if (hpriv->conf.enableAlwaysAck || hpriv->xmitAck != hpriv->recvSeq) {
591		gre->hasAck = 1;
592		be32enc(&gre->data[gre->hasSeq], hpriv->recvSeq);
593		hpriv->xmitAck = hpriv->recvSeq;
594		if (hpriv->conf.enableDelayedAck)
595			ng_uncallout(&hpriv->sackTimer, hpriv->node);
596	}
597
598	/* Prepend GRE header to outgoing frame */
599	grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
600	if (m == NULL) {
601		MGETHDR(m, M_NOWAIT, MT_DATA);
602		if (m == NULL) {
603			priv->stats.memoryFailures++;
604			ERROUT(ENOBUFS);
605		}
606		m->m_len = m->m_pkthdr.len = grelen;
607		m->m_pkthdr.rcvif = NULL;
608	} else {
609		M_PREPEND(m, grelen, M_NOWAIT);
610		if (m == NULL || (m->m_len < grelen
611		    && (m = m_pullup(m, grelen)) == NULL)) {
612			priv->stats.memoryFailures++;
613			ERROUT(ENOBUFS);
614		}
615	}
616	bcopy(gre, mtod(m, u_char *), grelen);
617
618	/* Update stats */
619	priv->stats.xmitPackets++;
620	priv->stats.xmitOctets += m->m_pkthdr.len;
621
622	/*
623	 * XXX: we should reset timer only after an item has been sent
624	 * successfully.
625	 */
626	if (hpriv->conf.enableWindowing &&
627	    gre->hasSeq && hpriv->xmitSeq == hpriv->recvAck + 1)
628		ng_pptpgre_start_recv_ack_timer(hpriv);
629
630	mtx_unlock(&hpriv->mtx);
631
632	/* Deliver packet */
633	if (item) {
634		NG_FWD_NEW_DATA(error, item, priv->lower, m);
635	} else {
636		NG_SEND_DATA_ONLY(error, priv->lower, m);
637	}
638
639	return (error);
640
641done:
642	mtx_unlock(&hpriv->mtx);
643	NG_FREE_M(m);
644	if (item)
645		NG_FREE_ITEM(item);
646	return (error);
647}
648
649/*
650 * Handle an incoming packet.  The packet includes the IP header.
651 */
652static int
653ng_pptpgre_rcvdata_lower(hook_p hook, item_p item)
654{
655	hpriv_p hpriv;
656	node_p node = NG_HOOK_NODE(hook);
657	const priv_p priv = NG_NODE_PRIVATE(node);
658	int iphlen, grelen, extralen;
659	const struct greheader *gre;
660	const struct ip *ip;
661	int error = 0;
662	struct mbuf *m;
663
664	NGI_GET_M(item, m);
665	/* Update stats */
666	priv->stats.recvPackets++;
667	priv->stats.recvOctets += m->m_pkthdr.len;
668
669	/* Sanity check packet length */
670	if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) {
671		priv->stats.recvRunts++;
672		ERROUT(EINVAL);
673	}
674
675	/* Safely pull up the complete IP+GRE headers */
676	if (m->m_len < sizeof(*ip) + sizeof(*gre)
677	    && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) {
678		priv->stats.memoryFailures++;
679		ERROUT(ENOBUFS);
680	}
681	ip = mtod(m, const struct ip *);
682	iphlen = ip->ip_hl << 2;
683	if (m->m_len < iphlen + sizeof(*gre)) {
684		if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) {
685			priv->stats.memoryFailures++;
686			ERROUT(ENOBUFS);
687		}
688		ip = mtod(m, const struct ip *);
689	}
690	gre = (const struct greheader *)((const u_char *)ip + iphlen);
691	grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
692	if (m->m_pkthdr.len < iphlen + grelen) {
693		priv->stats.recvRunts++;
694		ERROUT(EINVAL);
695	}
696	if (m->m_len < iphlen + grelen) {
697		if ((m = m_pullup(m, iphlen + grelen)) == NULL) {
698			priv->stats.memoryFailures++;
699			ERROUT(ENOBUFS);
700		}
701		ip = mtod(m, const struct ip *);
702		gre = (const struct greheader *)((const u_char *)ip + iphlen);
703	}
704
705	/* Sanity check packet length and GRE header bits */
706	extralen = m->m_pkthdr.len
707	    - (iphlen + grelen + gre->hasSeq * be16dec(&gre->length));
708	if (extralen < 0) {
709		priv->stats.recvBadGRE++;
710		ERROUT(EINVAL);
711	}
712	if ((be32dec(gre) & PPTP_INIT_MASK) != PPTP_INIT_VALUE) {
713		priv->stats.recvBadGRE++;
714		ERROUT(EINVAL);
715	}
716
717	hpriv = ng_pptpgre_find_session(priv, be16dec(&gre->cid));
718	if (hpriv == NULL || hpriv->hook == NULL || !hpriv->conf.enabled) {
719		priv->stats.recvBadCID++;
720		ERROUT(EINVAL);
721	}
722	mtx_lock(&hpriv->mtx);
723
724	/* Look for peer ack */
725	if (gre->hasAck) {
726		const u_int32_t	ack = be32dec(&gre->data[gre->hasSeq]);
727		const int index = ack - hpriv->recvAck - 1;
728		long sample;
729		long diff;
730
731		/* Sanity check ack value */
732		if (PPTP_SEQ_DIFF(ack, hpriv->xmitSeq) > 0) {
733			priv->stats.recvBadAcks++;
734			goto badAck;		/* we never sent it! */
735		}
736		if (PPTP_SEQ_DIFF(ack, hpriv->recvAck) <= 0)
737			goto badAck;		/* ack already timed out */
738		hpriv->recvAck = ack;
739
740		/* Update adaptive timeout stuff */
741		if (hpriv->conf.enableWindowing) {
742			sample = ng_pptpgre_time() - hpriv->timeSent[index];
743			diff = sample - hpriv->rtt;
744			hpriv->rtt += PPTP_ACK_ALPHA(diff);
745			if (diff < 0)
746				diff = -diff;
747			hpriv->dev += PPTP_ACK_BETA(diff - hpriv->dev);
748			    /* +2 to compensate low precision of int math */
749			hpriv->ato = hpriv->rtt + PPTP_ACK_CHI(hpriv->dev + 2);
750			if (hpriv->ato > PPTP_MAX_TIMEOUT)
751				hpriv->ato = PPTP_MAX_TIMEOUT;
752			else if (hpriv->ato < PPTP_MIN_TIMEOUT)
753				hpriv->ato = PPTP_MIN_TIMEOUT;
754
755			/* Shift packet transmit times in our transmit window */
756			bcopy(hpriv->timeSent + index + 1, hpriv->timeSent,
757			    sizeof(*hpriv->timeSent)
758			      * (PPTP_XMIT_WIN - (index + 1)));
759
760			/* If we sent an entire window, increase window size */
761			if (PPTP_SEQ_DIFF(ack, hpriv->winAck) >= 0
762			    && hpriv->xmitWin < PPTP_XMIT_WIN) {
763				hpriv->xmitWin++;
764				hpriv->winAck = ack + hpriv->xmitWin;
765			}
766
767			/* Stop/(re)start receive ACK timer as necessary */
768			ng_uncallout(&hpriv->rackTimer, hpriv->node);
769			if (hpriv->recvAck != hpriv->xmitSeq)
770				ng_pptpgre_start_recv_ack_timer(hpriv);
771		}
772	}
773badAck:
774
775	/* See if frame contains any data */
776	if (gre->hasSeq) {
777		const u_int32_t seq = be32dec(&gre->data[0]);
778
779		/* Sanity check sequence number */
780		if (PPTP_SEQ_DIFF(seq, hpriv->recvSeq) <= 0) {
781			if (seq == hpriv->recvSeq)
782				priv->stats.recvDuplicates++;
783			else
784				priv->stats.recvOutOfOrder++;
785			mtx_unlock(&hpriv->mtx);
786			ERROUT(EINVAL);
787		}
788		hpriv->recvSeq = seq;
789
790		/* We need to acknowledge this packet; do it soon... */
791		if (!(callout_pending(&hpriv->sackTimer))) {
792			/* If delayed ACK is disabled, send it now */
793			if (!hpriv->conf.enableDelayedAck) {	/* ack now */
794				ng_pptpgre_xmit(hpriv, NULL);
795				/* ng_pptpgre_xmit() drops the mutex */
796			} else {				/* ack later */
797				ng_pptpgre_start_send_ack_timer(hpriv);
798				mtx_unlock(&hpriv->mtx);
799			}
800		} else
801			mtx_unlock(&hpriv->mtx);
802
803		/* Trim mbuf down to internal payload */
804		m_adj(m, iphlen + grelen);
805		if (extralen > 0)
806			m_adj(m, -extralen);
807
808		mtx_assert(&hpriv->mtx, MA_NOTOWNED);
809
810		/* Deliver frame to upper layers */
811		NG_FWD_NEW_DATA(error, item, hpriv->hook, m);
812	} else {
813		priv->stats.recvLoneAcks++;
814		mtx_unlock(&hpriv->mtx);
815		NG_FREE_ITEM(item);
816		NG_FREE_M(m);		/* no data to deliver */
817	}
818
819	return (error);
820
821done:
822	NG_FREE_ITEM(item);
823	NG_FREE_M(m);
824	return (error);
825}
826
827/*************************************************************************
828		    TIMER RELATED FUNCTIONS
829*************************************************************************/
830
831/*
832 * Start a timer for the peer's acknowledging our oldest unacknowledged
833 * sequence number.  If we get an ack for this sequence number before
834 * the timer goes off, we cancel the timer.  Resets currently running
835 * recv ack timer, if any.
836 */
837static void
838ng_pptpgre_start_recv_ack_timer(hpriv_p hpriv)
839{
840	int remain, ticks;
841
842	/* Compute how long until oldest unack'd packet times out,
843	   and reset the timer to that time. */
844	remain = (hpriv->timeSent[0] + hpriv->ato) - ng_pptpgre_time();
845	if (remain < 0)
846		remain = 0;
847
848	/* Be conservative: timeout can happen up to 1 tick early */
849	ticks = (((remain * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE) + 1;
850	ng_callout(&hpriv->rackTimer, hpriv->node, hpriv->hook,
851	    ticks, ng_pptpgre_recv_ack_timeout, hpriv, 0);
852}
853
854/*
855 * The peer has failed to acknowledge the oldest unacknowledged sequence
856 * number within the time allotted.  Update our adaptive timeout parameters
857 * and reset/restart the recv ack timer.
858 */
859static void
860ng_pptpgre_recv_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2)
861{
862	const priv_p priv = NG_NODE_PRIVATE(node);
863	const hpriv_p hpriv = arg1;
864
865	/* Update adaptive timeout stuff */
866	priv->stats.recvAckTimeouts++;
867	hpriv->rtt = PPTP_ACK_DELTA(hpriv->rtt) + 1; /* +1 to avoid delta*0 case */
868	hpriv->ato = hpriv->rtt + PPTP_ACK_CHI(hpriv->dev);
869	if (hpriv->ato > PPTP_MAX_TIMEOUT)
870		hpriv->ato = PPTP_MAX_TIMEOUT;
871	else if (hpriv->ato < PPTP_MIN_TIMEOUT)
872		hpriv->ato = PPTP_MIN_TIMEOUT;
873
874	/* Reset ack and sliding window */
875	hpriv->recvAck = hpriv->xmitSeq;		/* pretend we got the ack */
876	hpriv->xmitWin = (hpriv->xmitWin + 1) / 2;	/* shrink transmit window */
877	hpriv->winAck = hpriv->recvAck + hpriv->xmitWin;	/* reset win expand time */
878}
879
880/*
881 * Start the send ack timer. This assumes the timer is not
882 * already running.
883 */
884static void
885ng_pptpgre_start_send_ack_timer(hpriv_p hpriv)
886{
887	int ackTimeout, ticks;
888
889	/* Take 1/4 of the estimated round trip time */
890	ackTimeout = (hpriv->rtt >> 2);
891	if (ackTimeout < PPTP_MIN_ACK_DELAY)
892		ackTimeout = PPTP_MIN_ACK_DELAY;
893	else if (ackTimeout > PPTP_MAX_ACK_DELAY)
894		ackTimeout = PPTP_MAX_ACK_DELAY;
895
896	/* Be conservative: timeout can happen up to 1 tick early */
897	ticks = (((ackTimeout * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE);
898	ng_callout(&hpriv->sackTimer, hpriv->node, hpriv->hook,
899	    ticks, ng_pptpgre_send_ack_timeout, hpriv, 0);
900}
901
902/*
903 * We've waited as long as we're willing to wait before sending an
904 * acknowledgement to the peer for received frames. We had hoped to
905 * be able to piggy back our acknowledgement on an outgoing data frame,
906 * but apparently there haven't been any since. So send the ack now.
907 */
908static void
909ng_pptpgre_send_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2)
910{
911	const hpriv_p hpriv = arg1;
912
913	mtx_lock(&hpriv->mtx);
914	/* Send a frame with an ack but no payload */
915  	ng_pptpgre_xmit(hpriv, NULL);
916	mtx_assert(&hpriv->mtx, MA_NOTOWNED);
917}
918
919/*************************************************************************
920		    MISC FUNCTIONS
921*************************************************************************/
922
923/*
924 * Find the hook with a given session ID.
925 */
926static hpriv_p
927ng_pptpgre_find_session(priv_p privp, u_int16_t cid)
928{
929	uint16_t	hash = SESSHASH(cid);
930	hpriv_p	hpriv = NULL;
931
932	LIST_FOREACH(hpriv, &privp->sesshash[hash], sessions) {
933		if (hpriv->conf.cid == cid)
934			break;
935	}
936
937	return (hpriv);
938}
939
940/*
941 * Reset state (must be called with lock held or from writer)
942 */
943static void
944ng_pptpgre_reset(hpriv_p hpriv)
945{
946	/* Reset adaptive timeout state */
947	hpriv->ato = PPTP_MAX_TIMEOUT;
948	hpriv->rtt = PPTP_TIME_SCALE / 10;
949	if (hpriv->conf.peerPpd > 1)	/* ppd = 0 treat as = 1 */
950		hpriv->rtt *= hpriv->conf.peerPpd;
951	hpriv->dev = 0;
952	hpriv->xmitWin = (hpriv->conf.recvWin + 1) / 2;
953	if (hpriv->xmitWin < 2)		/* often the first packet is lost */
954		hpriv->xmitWin = 2;		/*   because the peer isn't ready */
955	else if (hpriv->xmitWin > PPTP_XMIT_WIN)
956		hpriv->xmitWin = PPTP_XMIT_WIN;
957	hpriv->winAck = hpriv->xmitWin;
958
959	/* Reset sequence numbers */
960	hpriv->recvSeq = ~0;
961	hpriv->recvAck = ~0;
962	hpriv->xmitSeq = ~0;
963	hpriv->xmitAck = ~0;
964
965	/* Stop timers */
966	ng_uncallout(&hpriv->sackTimer, hpriv->node);
967	ng_uncallout(&hpriv->rackTimer, hpriv->node);
968}
969
970/*
971 * Return the current time scaled & translated to our internally used format.
972 */
973static pptptime_t
974ng_pptpgre_time(void)
975{
976	struct timeval tv;
977	pptptime_t t;
978
979	microuptime(&tv);
980	t = (pptptime_t)tv.tv_sec * PPTP_TIME_SCALE;
981	t += tv.tv_usec / (1000000 / PPTP_TIME_SCALE);
982	return(t);
983}
984