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