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