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