xref: /freebsd/sys/netgraph/ng_pptpgre.c (revision eacee0ff7ec955b32e09515246bd97b6edcd2b0f)
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_shutdown;
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, item_p item);
182 static int	ng_pptpgre_recv(node_p node, item_p item);
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_ABI_VERSION,
249 	NG_PPTPGRE_NODE_TYPE,
250 	NULL,
251 	ng_pptpgre_constructor,
252 	ng_pptpgre_rcvmsg,
253 	ng_pptpgre_shutdown,
254 	ng_pptpgre_newhook,
255 	NULL,
256 	NULL,
257 	ng_pptpgre_rcvdata,
258 	ng_pptpgre_disconnect,
259 	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 	callout_handle_init(&priv->ackp.sackTimer);
286 	callout_handle_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 */
414 	ng_pptpgre_reset(node);
415 
416 	/* Take down netgraph node */
417 	bzero(priv, sizeof(*priv));
418 	FREE(priv, M_NETGRAPH);
419 	NG_NODE_SET_PRIVATE(node, NULL);
420 	NG_NODE_UNREF(node);
421 	return (0);
422 }
423 
424 /*
425  * Hook disconnection
426  */
427 static int
428 ng_pptpgre_disconnect(hook_p hook)
429 {
430 	const node_p node = NG_HOOK_NODE(hook);
431 	const priv_p priv = NG_NODE_PRIVATE(node);
432 
433 	/* Zero out hook pointer */
434 	if (hook == priv->upper)
435 		priv->upper = NULL;
436 	else if (hook == priv->lower)
437 		priv->lower = NULL;
438 	else
439 		panic("%s: unknown hook", __func__);
440 
441 	/* Go away if no longer connected to anything */
442 	if ((NG_NODE_NUMHOOKS(node) == 0)
443 	&& (NG_NODE_IS_VALID(node)))
444 		ng_rmnode_self(node);
445 	return (0);
446 }
447 
448 /*************************************************************************
449 		    TRANSMIT AND RECEIVE FUNCTIONS
450 *************************************************************************/
451 
452 /*
453  * Transmit an outgoing frame, or just an ack if m is NULL.
454  */
455 static int
456 ng_pptpgre_xmit(node_p node, item_p item)
457 {
458 	const priv_p priv = NG_NODE_PRIVATE(node);
459 	struct ng_pptpgre_ackp *const a = &priv->ackp;
460 	u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)];
461 	struct greheader *const gre = (struct greheader *)buf;
462 	int grelen, error;
463 	struct mbuf *m;
464 
465 	if (item) {
466 		NGI_GET_M(item, m);
467 	} else {
468 		m = NULL;
469 	}
470 	/* Check if there's data */
471 	if (m != NULL) {
472 
473 		/* Is our transmit window full? */
474 		if ((u_int32_t)PPTP_SEQ_DIFF(priv->xmitSeq, priv->recvAck)
475 		      >= a->xmitWin) {
476 			priv->stats.xmitDrops++;
477 			NG_FREE_M(m);
478 			NG_FREE_ITEM(item);
479 			return (ENOBUFS);
480 		}
481 
482 		/* Sanity check frame length */
483 		if (m != NULL && m->m_pkthdr.len > PPTP_MAX_PAYLOAD) {
484 			priv->stats.xmitTooBig++;
485 			NG_FREE_M(m);
486 			NG_FREE_ITEM(item);
487 			return (EMSGSIZE);
488 		}
489 	} else {
490 		priv->stats.xmitLoneAcks++;
491 	}
492 
493 	/* Build GRE header */
494 	((u_int32_t *)gre)[0] = htonl(PPTP_INIT_VALUE);
495 	gre->length = (m != NULL) ? htons((u_short)m->m_pkthdr.len) : 0;
496 	gre->cid = htons(priv->conf.peerCid);
497 
498 	/* Include sequence number if packet contains any data */
499 	if (m != NULL) {
500 		gre->hasSeq = 1;
501 		a->timeSent[priv->xmitSeq - priv->recvAck]
502 		    = ng_pptpgre_time(node);
503 		priv->xmitSeq++;
504 		gre->data[0] = htonl(priv->xmitSeq);
505 	}
506 
507 	/* Include acknowledgement (and stop send ack timer) if needed */
508 	if (priv->conf.enableAlwaysAck || priv->xmitAck != priv->recvSeq) {
509 		gre->hasAck = 1;
510 		gre->data[gre->hasSeq] = htonl(priv->recvSeq);
511 		priv->xmitAck = priv->recvSeq;
512 		a->sackTimerPtr = NULL;		/* "stop" timer */
513 	}
514 
515 	/* Prepend GRE header to outgoing frame */
516 	grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
517 	if (m == NULL) {
518 		MGETHDR(m, M_DONTWAIT, MT_DATA);
519 		if (m == NULL) {
520 			priv->stats.memoryFailures++;
521 			if (item)
522 				NG_FREE_ITEM(item);
523 			return (ENOBUFS);
524 		}
525 		m->m_len = m->m_pkthdr.len = grelen;
526 		m->m_pkthdr.rcvif = NULL;
527 	} else {
528 		M_PREPEND(m, grelen, M_NOWAIT);
529 		if (m == NULL || (m->m_len < grelen
530 		    && (m = m_pullup(m, grelen)) == NULL)) {
531 			priv->stats.memoryFailures++;
532 			if (item)
533 				NG_FREE_ITEM(item);
534 			return (ENOBUFS);
535 		}
536 	}
537 	bcopy(gre, mtod(m, u_char *), grelen);
538 
539 	/* Update stats */
540 	priv->stats.xmitPackets++;
541 	priv->stats.xmitOctets += m->m_pkthdr.len;
542 
543 	/* Deliver packet */
544 	if (item) {
545 		NG_FWD_NEW_DATA(error, item, priv->lower, m);
546 	} else {
547 		NG_SEND_DATA_ONLY(error, priv->lower, m);
548 	}
549 
550 
551 	/* Start receive ACK timer if data was sent and not already running */
552 	if (error == 0 && gre->hasSeq && priv->xmitSeq == priv->recvAck + 1)
553 		ng_pptpgre_start_recv_ack_timer(node);
554 	return (error);
555 }
556 
557 /*
558  * Handle an incoming packet.  The packet includes the IP header.
559  */
560 static int
561 ng_pptpgre_recv(node_p node, item_p item)
562 {
563 	const priv_p priv = NG_NODE_PRIVATE(node);
564 	int iphlen, grelen, extralen;
565 	struct greheader *gre;
566 	struct ip *ip;
567 	int error = 0;
568 	struct mbuf *m;
569 
570 	NGI_GET_M(item, m);
571 	/* Update stats */
572 	priv->stats.recvPackets++;
573 	priv->stats.recvOctets += m->m_pkthdr.len;
574 
575 	/* Sanity check packet length */
576 	if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) {
577 		priv->stats.recvRunts++;
578 bad:
579 		NG_FREE_M(m);
580 		NG_FREE_ITEM(item);
581 		return (EINVAL);
582 	}
583 
584 	/* Safely pull up the complete IP+GRE headers */
585 	if (m->m_len < sizeof(*ip) + sizeof(*gre)
586 	    && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) {
587 		priv->stats.memoryFailures++;
588 		NG_FREE_ITEM(item);
589 		return (ENOBUFS);
590 	}
591 	ip = mtod(m, struct ip *);
592 	iphlen = ip->ip_hl << 2;
593 	if (m->m_len < iphlen + sizeof(*gre)) {
594 		if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) {
595 			priv->stats.memoryFailures++;
596 			NG_FREE_ITEM(item);
597 			return (ENOBUFS);
598 		}
599 		ip = mtod(m, struct ip *);
600 	}
601 	gre = (struct greheader *)((u_char *)ip + iphlen);
602 	grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
603 	if (m->m_pkthdr.len < iphlen + grelen) {
604 		priv->stats.recvRunts++;
605 		goto bad;
606 	}
607 	if (m->m_len < iphlen + grelen) {
608 		if ((m = m_pullup(m, iphlen + grelen)) == NULL) {
609 			priv->stats.memoryFailures++;
610 			NG_FREE_ITEM(item);
611 			return (ENOBUFS);
612 		}
613 		ip = mtod(m, struct ip *);
614 		gre = (struct greheader *)((u_char *)ip + iphlen);
615 	}
616 
617 	/* Sanity check packet length and GRE header bits */
618 	extralen = m->m_pkthdr.len
619 	    - (iphlen + grelen + (u_int16_t)ntohs(gre->length));
620 	if (extralen < 0) {
621 		priv->stats.recvBadGRE++;
622 		goto bad;
623 	}
624 	if ((ntohl(*((u_int32_t *)gre)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE) {
625 		priv->stats.recvBadGRE++;
626 		goto bad;
627 	}
628 	if (ntohs(gre->cid) != priv->conf.cid) {
629 		priv->stats.recvBadCID++;
630 		goto bad;
631 	}
632 
633 	/* Look for peer ack */
634 	if (gre->hasAck) {
635 		struct ng_pptpgre_ackp *const a = &priv->ackp;
636 		const u_int32_t	ack = ntohl(gre->data[gre->hasSeq]);
637 		const int index = ack - priv->recvAck - 1;
638 		long sample;
639 		long diff;
640 
641 		/* Sanity check ack value */
642 		if (PPTP_SEQ_DIFF(ack, priv->xmitSeq) > 0) {
643 			priv->stats.recvBadAcks++;
644 			goto badAck;		/* we never sent it! */
645 		}
646 		if (PPTP_SEQ_DIFF(ack, priv->recvAck) <= 0)
647 			goto badAck;		/* ack already timed out */
648 		priv->recvAck = ack;
649 
650 		/* Update adaptive timeout stuff */
651 		sample = ng_pptpgre_time(node) - a->timeSent[index];
652 		diff = sample - a->rtt;
653 		a->rtt += PPTP_ACK_ALPHA(diff);
654 		if (diff < 0)
655 			diff = -diff;
656 		a->dev += PPTP_ACK_BETA(diff - a->dev);
657 		a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
658 		if (a->ato > PPTP_MAX_TIMEOUT)
659 			a->ato = PPTP_MAX_TIMEOUT;
660 		if (a->ato < PPTP_MIN_TIMEOUT)
661 			a->ato = PPTP_MIN_TIMEOUT;
662 
663 		/* Shift packet transmit times in our transmit window */
664 		ovbcopy(a->timeSent + index + 1, a->timeSent,
665 		    sizeof(*a->timeSent) * (PPTP_XMIT_WIN - (index + 1)));
666 
667 		/* If we sent an entire window, increase window size by one */
668 		if (PPTP_SEQ_DIFF(ack, a->winAck) >= 0
669 		    && a->xmitWin < PPTP_XMIT_WIN) {
670 			a->xmitWin++;
671 			a->winAck = ack + a->xmitWin;
672 		}
673 
674 		/* Stop/(re)start receive ACK timer as necessary */
675 		a->rackTimerPtr = NULL;
676 		if (priv->recvAck != priv->xmitSeq)
677 			ng_pptpgre_start_recv_ack_timer(node);
678 	}
679 badAck:
680 
681 	/* See if frame contains any data */
682 	if (gre->hasSeq) {
683 		struct ng_pptpgre_ackp *const a = &priv->ackp;
684 		const u_int32_t seq = ntohl(gre->data[0]);
685 
686 		/* Sanity check sequence number */
687 		if (PPTP_SEQ_DIFF(seq, priv->recvSeq) <= 0) {
688 			if (seq == priv->recvSeq)
689 				priv->stats.recvDuplicates++;
690 			else
691 				priv->stats.recvOutOfOrder++;
692 			goto bad;		/* out-of-order or dup */
693 		}
694 		priv->recvSeq = seq;
695 
696 		/* We need to acknowledge this packet; do it soon... */
697 		if (a->sackTimerPtr == NULL) {
698 			int maxWait;
699 
700 			/* Take 1/4 of the estimated round trip time */
701 			maxWait = (a->rtt >> 2);
702 
703 			/* If delayed ACK is disabled, send it now */
704 			if (!priv->conf.enableDelayedAck
705 			    || maxWait < PPTP_MIN_ACK_DELAY)
706 				ng_pptpgre_xmit(node, NULL);
707 			else {			/* send the ack later */
708 				if (maxWait > PPTP_MAX_ACK_DELAY)
709 					maxWait = PPTP_MAX_ACK_DELAY;
710 				ng_pptpgre_start_send_ack_timer(node, maxWait);
711 			}
712 		}
713 
714 		/* Trim mbuf down to internal payload */
715 		m_adj(m, iphlen + grelen);
716 		if (extralen > 0)
717 			m_adj(m, -extralen);
718 
719 		/* Deliver frame to upper layers */
720 		NG_FWD_NEW_DATA(error, item, priv->upper, m);
721 	} else {
722 		priv->stats.recvLoneAcks++;
723 		NG_FREE_ITEM(item);
724 		NG_FREE_M(m);		/* no data to deliver */
725 	}
726 	return (error);
727 }
728 
729 /*************************************************************************
730 		    TIMER RELATED FUNCTIONS
731 *************************************************************************/
732 
733 /*
734  * Start a timer for the peer's acknowledging our oldest unacknowledged
735  * sequence number.  If we get an ack for this sequence number before
736  * the timer goes off, we cancel the timer.  Resets currently running
737  * recv ack timer, if any.
738  */
739 static void
740 ng_pptpgre_start_recv_ack_timer(node_p node)
741 {
742 	const priv_p priv = NG_NODE_PRIVATE(node);
743 	struct ng_pptpgre_ackp *const a = &priv->ackp;
744 	int remain, ticks;
745 
746 	/* Compute how long until oldest unack'd packet times out,
747 	   and reset the timer to that time. */
748 	KASSERT(a->rackTimerPtr == NULL, ("%s: rackTimer", __func__));
749 	remain = (a->timeSent[0] + a->ato) - ng_pptpgre_time(node);
750 	if (remain < 0)
751 		remain = 0;
752 #ifdef DEBUG_RAT
753 	a->timerLength = remain;
754 	a->timerStart = ng_pptpgre_time(node);
755 #endif
756 
757 	/* Start new timer */
758 	MALLOC(a->rackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT);
759 	if (a->rackTimerPtr == NULL) {
760 		priv->stats.memoryFailures++;
761 		return;			/* XXX potential hang here */
762 	}
763 	*a->rackTimerPtr = node;	/* insures the correct timeout event */
764 	NG_NODE_REF(node);
765 
766 	/* Be conservative: timeout() can return up to 1 tick early */
767 	ticks = (((remain * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE) + 1;
768 	a->rackTimer = timeout(ng_pptpgre_recv_ack_timeout,
769 	    a->rackTimerPtr, ticks);
770 }
771 
772 /*
773  * The peer has failed to acknowledge the oldest unacknowledged sequence
774  * number within the time allotted.  Update our adaptive timeout parameters
775  * and reset/restart the recv ack timer.
776  */
777 static void
778 ng_pptpgre_recv_ack_timeout(void *arg)
779 {
780 	int s = splnet();
781 	const node_p node = *((node_p *)arg);
782 	const priv_p priv = NG_NODE_PRIVATE(node);
783 	struct ng_pptpgre_ackp *const a = &priv->ackp;
784 
785 	/* This complicated stuff is needed to avoid race conditions */
786 	FREE(arg, M_NETGRAPH);
787 	KASSERT(node->nd_refs > 0, ("%s: no nd_refs", __func__));
788 	if (NG_NODE_NOT_VALID(node)) {	/* shutdown race condition */
789 		NG_NODE_UNREF(node);
790 		splx(s);
791 		return;
792 	}
793 	if (arg != a->rackTimerPtr) {	/* timer stopped race condition */
794 		NG_NODE_UNREF(node);
795 		splx(s);
796 		return;
797 	}
798 	a->rackTimerPtr = NULL;
799 
800 	/* Update adaptive timeout stuff */
801 	priv->stats.recvAckTimeouts++;
802 	a->rtt = PPTP_ACK_DELTA(a->rtt);
803 	a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
804 	if (a->ato > PPTP_MAX_TIMEOUT)
805 		a->ato = PPTP_MAX_TIMEOUT;
806 	if (a->ato < PPTP_MIN_TIMEOUT)
807 		a->ato = PPTP_MIN_TIMEOUT;
808 
809 #ifdef DEBUG_RAT
810     log(LOG_DEBUG,
811 	"RAT now=%d seq=0x%x sent=%d tstart=%d tlen=%d ato=%d\n",
812 	(int)ng_pptpgre_time(node), priv->recvAck + 1,
813 	(int)a->timeSent[0], (int)a->timerStart, (int)a->timerLength, a->ato);
814 #endif
815 
816 	/* Reset ack and sliding window */
817 	priv->recvAck = priv->xmitSeq;		/* pretend we got the ack */
818 	a->xmitWin = (a->xmitWin + 1) / 2;	/* shrink transmit window */
819 	a->winAck = priv->recvAck + a->xmitWin;	/* reset win expand time */
820 	NG_NODE_UNREF(node);
821 	splx(s);
822 }
823 
824 /*
825  * Start the send ack timer. This assumes the timer is not
826  * already running.
827  */
828 static void
829 ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout)
830 {
831 	const priv_p priv = NG_NODE_PRIVATE(node);
832 	struct ng_pptpgre_ackp *const a = &priv->ackp;
833 	int ticks;
834 
835 	/* Start new timer */
836 	KASSERT(a->sackTimerPtr == NULL, ("%s: sackTimer", __func__));
837 	MALLOC(a->sackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT);
838 	if (a->sackTimerPtr == NULL) {
839 		priv->stats.memoryFailures++;
840 		return;			/* XXX potential hang here */
841 	}
842 	*a->sackTimerPtr = node;
843 	NG_NODE_REF(node);
844 
845 	/* Be conservative: timeout() can return up to 1 tick early */
846 	ticks = (((ackTimeout * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE);
847 	a->sackTimer = timeout(ng_pptpgre_send_ack_timeout,
848 	    a->sackTimerPtr, ticks);
849 }
850 
851 /*
852  * We've waited as long as we're willing to wait before sending an
853  * acknowledgement to the peer for received frames. We had hoped to
854  * be able to piggy back our acknowledgement on an outgoing data frame,
855  * but apparently there haven't been any since. So send the ack now.
856  */
857 static void
858 ng_pptpgre_send_ack_timeout(void *arg)
859 {
860 	int s = splnet();
861 	const node_p node = *((node_p *)arg);
862 	const priv_p priv = NG_NODE_PRIVATE(node);
863 	struct ng_pptpgre_ackp *const a = &priv->ackp;
864 
865 	/* This complicated stuff is needed to avoid race conditions */
866 	FREE(arg, M_NETGRAPH);
867 	KASSERT(node->nd_refs > 0, ("%s: no nd_refs", __func__));
868 	if (NG_NODE_NOT_VALID(node)) {	/* shutdown race condition */
869 		NG_NODE_UNREF(node);
870 		splx(s);
871 		return;
872 	}
873 	if (a->sackTimerPtr != arg) {	/* timer stopped race condition */
874 		NG_NODE_UNREF(node);
875 		splx(s);
876 		return;
877 	}
878 	a->sackTimerPtr = NULL;
879 
880 	/* Send a frame with an ack but no payload */
881   	ng_pptpgre_xmit(node, NULL);
882 	NG_NODE_UNREF(node);
883 	splx(s);
884 }
885 
886 /*************************************************************************
887 		    MISC FUNCTIONS
888 *************************************************************************/
889 
890 /*
891  * Reset state
892  */
893 static void
894 ng_pptpgre_reset(node_p node)
895 {
896 	const priv_p priv = NG_NODE_PRIVATE(node);
897 	struct ng_pptpgre_ackp *const a = &priv->ackp;
898 
899 	/* Reset adaptive timeout state */
900 	a->ato = PPTP_MAX_TIMEOUT;
901 	a->rtt = priv->conf.peerPpd * PPTP_TIME_SCALE / 10;  /* ppd in 10ths */
902 	if (a->rtt < PPTP_MIN_RTT)
903 		a->rtt = PPTP_MIN_RTT;
904 	a->dev = 0;
905 	a->xmitWin = (priv->conf.recvWin + 1) / 2;
906 	if (a->xmitWin < 2)		/* often the first packet is lost */
907 		a->xmitWin = 2;		/*   because the peer isn't ready */
908 	if (a->xmitWin > PPTP_XMIT_WIN)
909 		a->xmitWin = PPTP_XMIT_WIN;
910 	a->winAck = a->xmitWin;
911 
912 	/* Reset sequence numbers */
913 	priv->recvSeq = ~0;
914 	priv->recvAck = ~0;
915 	priv->xmitSeq = ~0;
916 	priv->xmitAck = ~0;
917 
918 	/* Reset start time */
919 	getmicrouptime(&priv->startTime);
920 
921 	/* Reset stats */
922 	bzero(&priv->stats, sizeof(priv->stats));
923 
924 	/* "Stop" timers */
925 	a->sackTimerPtr = NULL;
926 	a->rackTimerPtr = NULL;
927 }
928 
929 /*
930  * Return the current time scaled & translated to our internally used format.
931  */
932 static pptptime_t
933 ng_pptpgre_time(node_p node)
934 {
935 	const priv_p priv = NG_NODE_PRIVATE(node);
936 	struct timeval tv;
937 	pptptime_t t;
938 
939 	microuptime(&tv);
940 	if (tv.tv_sec < priv->startTime.tv_sec
941 	    || (tv.tv_sec == priv->startTime.tv_sec
942 	      && tv.tv_usec < priv->startTime.tv_usec))
943 		return (0);
944 	timevalsub(&tv, &priv->startTime);
945 	t = (pptptime_t)tv.tv_sec * PPTP_TIME_SCALE;
946 	t += (pptptime_t)tv.tv_usec / (1000000 / PPTP_TIME_SCALE);
947 	return(t);
948 }
949 
950