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