xref: /freebsd/sys/netgraph/ng_pptpgre.c (revision 5129159789cc9d7bc514e4546b88e3427695002d)
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/conf.h>
61 #include <sys/mbuf.h>
62 #include <sys/malloc.h>
63 #include <sys/errno.h>
64 #include <sys/socket.h>
65 #include <sys/syslog.h>
66 #include <sys/ctype.h>
67 
68 #include <netinet/in.h>
69 #include <netinet/in_systm.h>
70 #include <netinet/ip.h>
71 
72 #include <netgraph/ng_message.h>
73 #include <netgraph/netgraph.h>
74 #include <netgraph/ng_parse.h>
75 #include <netgraph/ng_pptpgre.h>
76 
77 /* GRE packet format, as used by PPTP */
78 struct greheader {
79 #if BYTE_ORDER == LITTLE_ENDIAN
80 	u_char		recursion:3;		/* recursion control */
81 	u_char		ssr:1;			/* strict source route */
82 	u_char		hasSeq:1;		/* sequence number present */
83 	u_char		hasKey:1;		/* key present */
84 	u_char		hasRoute:1;		/* routing present */
85 	u_char		hasSum:1;		/* checksum present */
86 	u_char		vers:3;			/* version */
87 	u_char		flags:4;		/* flags */
88 	u_char		hasAck:1;		/* acknowlege number present */
89 #elif BYTE_ORDER == BIG_ENDIAN
90 	u_char		hasSum:1;		/* checksum present */
91 	u_char		hasRoute:1;		/* routing present */
92 	u_char		hasKey:1;		/* key present */
93 	u_char		hasSeq:1;		/* sequence number present */
94 	u_char		ssr:1;			/* strict source route */
95 	u_char		recursion:3;		/* recursion control */
96 	u_char		hasAck:1;		/* acknowlege number present */
97 	u_char		flags:4;		/* flags */
98 	u_char		vers:3;			/* version */
99 #else
100 #error BYTE_ORDER is not defined properly
101 #endif
102 	u_int16_t	proto;			/* protocol (ethertype) */
103 	u_int16_t	length;			/* payload length */
104 	u_int16_t	cid;			/* call id */
105 	u_int32_t	data[0];		/* opt. seq, ack, then data */
106 };
107 
108 /* The PPTP protocol ID used in the GRE 'proto' field */
109 #define PPTP_GRE_PROTO		0x880b
110 
111 /* Bits that must be set a certain way in all PPTP/GRE packets */
112 #define PPTP_INIT_VALUE		((0x2001 << 16) | PPTP_GRE_PROTO)
113 #define PPTP_INIT_MASK		0xef7fffff
114 
115 /* Min and max packet length */
116 #define PPTP_MAX_PAYLOAD	(0xffff - sizeof(struct greheader) - 8)
117 
118 /* All times are scaled by this (PPTP_TIME_SCALE time units = 1 sec.) */
119 #define PPTP_TIME_SCALE		1000
120 typedef u_int32_t		pptptime_t;
121 
122 /* Acknowledgment timeout parameters and functions */
123 #define PPTP_XMIT_WIN		8			/* max xmit window */
124 #define PPTP_MIN_RTT		(PPTP_TIME_SCALE / 10)	/* 1/10 second */
125 #define PPTP_MAX_TIMEOUT	(10 * PPTP_TIME_SCALE)	/* 10 seconds */
126 
127 #define PPTP_ACK_ALPHA(x)	((x) >> 3)	/* alpha = 0.125 */
128 #define PPTP_ACK_BETA(x)	((x) >> 2)	/* beta = 0.25 */
129 #define PPTP_ACK_CHI(x) 	((x) << 2)	/* chi = 4 */
130 #define PPTP_ACK_DELTA(x) 	((x) << 1)	/* delta = 2 */
131 
132 /* We keep packet retransmit and acknowlegement state in this struct */
133 struct ng_pptpgre_ackp {
134 	int32_t			ato;		/* adaptive time-out value */
135 	int32_t			rtt;		/* round trip time estimate */
136 	int32_t			dev;		/* deviation estimate */
137 	u_int16_t		xmitWin;	/* size of xmit window */
138 	u_char			sackTimerRunning;/* send ack timer is running */
139 	u_int32_t		winAck;		/* seq when xmitWin will grow */
140 	struct callout_handle	sackTimer;	/* send ack timer */
141 	struct callout_handle	rackTimer;	/* recv ack timer */
142 	pptptime_t		timeSent[PPTP_XMIT_WIN];
143 };
144 
145 /* When we recieve a packet, we wait to see if there's an outgoing packet
146    we can piggy-back the ACK off of.  These parameters determine the mimimum
147    and maxmimum length of time we're willing to wait in order to do that. */
148 #define PPTP_MAX_ACK_DELAY	((int) (0.25 * PPTP_TIME_SCALE))
149 
150 /* Node private data */
151 struct ng_pptpgre_private {
152 	hook_p			upper;		/* hook to upper layers */
153 	hook_p			lower;		/* hook to lower layers */
154 	struct ng_pptpgre_conf	conf;		/* configuration info */
155 	struct ng_pptpgre_ackp	ackp;		/* packet transmit ack state */
156 	u_int32_t		recvSeq;	/* last seq # we rcv'd */
157 	u_int32_t		xmitSeq;	/* last seq # we sent */
158 	u_int32_t		recvAck;	/* last seq # peer ack'd */
159 	u_int32_t		xmitAck;	/* last seq # we ack'd */
160 	struct timeval		startTime;	/* time node was created */
161 };
162 typedef struct ng_pptpgre_private *priv_p;
163 
164 /* Netgraph node methods */
165 static ng_constructor_t	ng_pptpgre_constructor;
166 static ng_rcvmsg_t	ng_pptpgre_rcvmsg;
167 static ng_shutdown_t	ng_pptpgre_rmnode;
168 static ng_newhook_t	ng_pptpgre_newhook;
169 static ng_rcvdata_t	ng_pptpgre_rcvdata;
170 static ng_disconnect_t	ng_pptpgre_disconnect;
171 
172 /* Helper functions */
173 static int	ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta);
174 static int	ng_pptpgre_recv(node_p node, struct mbuf *m, meta_p meta);
175 static void	ng_pptpgre_start_recv_ack_timer(node_p node);
176 static void	ng_pptpgre_recv_ack_timeout(void *arg);
177 static void	ng_pptpgre_send_ack_timeout(void *arg);
178 static void	ng_pptpgre_reset(node_p node);
179 static pptptime_t ng_pptpgre_time(node_p node);
180 
181 /* Parse type for struct ng_pptpgre_conf */
182 static const struct ng_parse_struct_info
183 	ng_pptpgre_conf_type_info = NG_PPTPGRE_CONF_TYPE_INFO;
184 static const struct ng_parse_type ng_pptpgre_conf_type = {
185 	&ng_parse_struct_type,
186 	&ng_pptpgre_conf_type_info,
187 };
188 
189 /* List of commands and how to convert arguments to/from ASCII */
190 static const struct ng_cmdlist ng_pptpgre_cmdlist[] = {
191 	{
192 	  NGM_PPTPGRE_COOKIE,
193 	  NGM_PPTPGRE_SET_CONFIG,
194 	  "setconfig",
195 	  &ng_pptpgre_conf_type,
196 	  NULL
197 	},
198 	{
199 	  NGM_PPTPGRE_COOKIE,
200 	  NGM_PPTPGRE_GET_CONFIG,
201 	  "getconfig",
202 	  NULL,
203 	  &ng_pptpgre_conf_type
204 	},
205 	{ 0 }
206 };
207 
208 /* Node type descriptor */
209 static struct ng_type ng_pptpgre_typestruct = {
210 	NG_VERSION,
211 	NG_PPTPGRE_NODE_TYPE,
212 	NULL,
213 	ng_pptpgre_constructor,
214 	ng_pptpgre_rcvmsg,
215 	ng_pptpgre_rmnode,
216 	ng_pptpgre_newhook,
217 	NULL,
218 	NULL,
219 	ng_pptpgre_rcvdata,
220 	ng_pptpgre_rcvdata,
221 	ng_pptpgre_disconnect,
222 	ng_pptpgre_cmdlist
223 };
224 NETGRAPH_INIT(pptpgre, &ng_pptpgre_typestruct);
225 
226 #define ERROUT(x)	do { error = (x); goto done; } while (0)
227 
228 /************************************************************************
229 			NETGRAPH NODE STUFF
230  ************************************************************************/
231 
232 /*
233  * Node type constructor
234  */
235 static int
236 ng_pptpgre_constructor(node_p *nodep)
237 {
238 	priv_p priv;
239 	int error;
240 
241 	/* Allocate private structure */
242 	MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK);
243 	if (priv == NULL)
244 		return (ENOMEM);
245 	bzero(priv, sizeof(*priv));
246 
247 	/* Call generic node constructor */
248 	if ((error = ng_make_node_common(&ng_pptpgre_typestruct, nodep))) {
249 		FREE(priv, M_NETGRAPH);
250 		return (error);
251 	}
252 	(*nodep)->private = priv;
253 
254 	/* Initialize state */
255 	callout_handle_init(&priv->ackp.sackTimer);
256 	callout_handle_init(&priv->ackp.rackTimer);
257 
258 	/* Done */
259 	return (0);
260 }
261 
262 /*
263  * Give our OK for a hook to be added.
264  */
265 static int
266 ng_pptpgre_newhook(node_p node, hook_p hook, const char *name)
267 {
268 	const priv_p priv = node->private;
269 	hook_p *hookPtr;
270 
271 	/* Check hook name */
272 	if (strcmp(name, NG_PPTPGRE_HOOK_UPPER) == 0)
273 		hookPtr = &priv->upper;
274 	else if (strcmp(name, NG_PPTPGRE_HOOK_LOWER) == 0)
275 		hookPtr = &priv->lower;
276 	else
277 		return (EINVAL);
278 
279 	/* See if already connected */
280 	if (*hookPtr != NULL)
281 		return (EISCONN);
282 
283 	/* OK */
284 	*hookPtr = hook;
285 	return (0);
286 }
287 
288 /*
289  * Receive a control message.
290  */
291 static int
292 ng_pptpgre_rcvmsg(node_p node, struct ng_mesg *msg,
293 	      const char *raddr, struct ng_mesg **rptr)
294 {
295 	const priv_p priv = node->private;
296 	struct ng_mesg *resp = NULL;
297 	int error = 0;
298 
299 	switch (msg->header.typecookie) {
300 	case NGM_PPTPGRE_COOKIE:
301 		switch (msg->header.cmd) {
302 		case NGM_PPTPGRE_SET_CONFIG:
303 		    {
304 			struct ng_pptpgre_conf *const newConf =
305 				(struct ng_pptpgre_conf *) msg->data;
306 
307 			/* Check for invalid or illegal config */
308 			if (msg->header.arglen != sizeof(*newConf))
309 				ERROUT(EINVAL);
310 			ng_pptpgre_reset(node);		/* reset on configure */
311 			priv->conf = *newConf;
312 			break;
313 		    }
314 		case NGM_PPTPGRE_GET_CONFIG:
315 			NG_MKRESPONSE(resp, msg, sizeof(priv->conf), M_NOWAIT);
316 			if (resp == NULL)
317 				ERROUT(ENOMEM);
318 			bcopy(&priv->conf, resp->data, sizeof(priv->conf));
319 			break;
320 		default:
321 			error = EINVAL;
322 			break;
323 		}
324 		break;
325 	default:
326 		error = EINVAL;
327 		break;
328 	}
329 	if (rptr)
330 		*rptr = resp;
331 	else if (resp)
332 		FREE(resp, M_NETGRAPH);
333 
334 done:
335 	FREE(msg, M_NETGRAPH);
336 	return (error);
337 }
338 
339 /*
340  * Receive incoming data on a hook.
341  */
342 static int
343 ng_pptpgre_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
344 {
345 	const node_p node = hook->node;
346 	const priv_p priv = node->private;
347 
348 	/* If not configured, reject */
349 	if (!priv->conf.enabled) {
350 		NG_FREE_DATA(m, meta);
351 		return (ENXIO);
352 	}
353 
354 	/* Treat as xmit or recv data */
355 	if (hook == priv->upper)
356 		return ng_pptpgre_xmit(node, m, meta);
357 	if (hook == priv->lower)
358 		return ng_pptpgre_recv(node, m, meta);
359 	panic("%s: weird hook", __FUNCTION__);
360 }
361 
362 /*
363  * Destroy node
364  */
365 static int
366 ng_pptpgre_rmnode(node_p node)
367 {
368 	const priv_p priv = node->private;
369 
370 	/* Cancel timers */
371 	ng_pptpgre_reset(node);
372 
373 	/* Take down netgraph node */
374 	node->flags |= NG_INVALID;
375 	ng_cutlinks(node);
376 	ng_unname(node);
377 	bzero(priv, sizeof(*priv));
378 	FREE(priv, M_NETGRAPH);
379 	node->private = NULL;
380 	ng_unref(node);
381 	return (0);
382 }
383 
384 /*
385  * Hook disconnection
386  */
387 static int
388 ng_pptpgre_disconnect(hook_p hook)
389 {
390 	const node_p node = hook->node;
391 	const priv_p priv = node->private;
392 
393 	/* Zero out hook pointer */
394 	if (hook == priv->upper)
395 		priv->upper = NULL;
396 	else if (hook == priv->lower)
397 		priv->lower = NULL;
398 	else
399 		panic("%s: unknown hook", __FUNCTION__);
400 
401 	/* Go away if no longer connected to anything */
402 	if (node->numhooks == 0)
403 		ng_rmnode(node);
404 	return (0);
405 }
406 
407 /*************************************************************************
408 		    TRANSMIT AND RECEIVE FUNCTIONS
409 *************************************************************************/
410 
411 /*
412  * Transmit an outgoing frame, or just an ack if m is NULL.
413  */
414 static int
415 ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta)
416 {
417 	const priv_p priv = node->private;
418 	struct ng_pptpgre_ackp *const a = &priv->ackp;
419 	u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)];
420 	struct greheader *const gre = (struct greheader *)buf;
421 	int grelen, error;
422 
423 	/* Is our transmit window full? */
424 	if (m != NULL && priv->xmitSeq - priv->recvAck >= a->xmitWin) {
425 		NG_FREE_DATA(m, meta);
426 		return (ENOBUFS);
427 	}
428 
429 	/* Sanity check frame length */
430 	if (m != NULL && m->m_pkthdr.len > PPTP_MAX_PAYLOAD) {
431 		NG_FREE_DATA(m, meta);
432 		return (EMSGSIZE);
433 	}
434 
435 	/* Build GRE header */
436 	((u_int32_t *) gre)[0] = htonl(PPTP_INIT_VALUE);
437 	gre->length = (m != NULL) ? htons((u_short)m->m_pkthdr.len) : 0;
438 	gre->cid = htons(priv->conf.peerCid);
439 
440 	/* Include sequence number if packet contains any data */
441 	if (m != NULL) {
442 		gre->hasSeq = 1;
443 		a->timeSent[priv->xmitSeq - priv->recvAck]
444 		    = ng_pptpgre_time(node);
445 		priv->xmitSeq++;
446 		gre->data[0] = htonl(priv->xmitSeq);
447 		if (priv->xmitSeq == priv->recvAck + 1)
448 			ng_pptpgre_start_recv_ack_timer(node);
449 	}
450 
451 	/* Include acknowledgement (and stop send ack timer) if needed */
452 	if (priv->xmitAck < priv->recvSeq) {
453 		gre->hasAck = 1;
454 		priv->xmitAck = priv->recvSeq;
455 		gre->data[gre->hasSeq] = htonl(priv->xmitAck);
456 		if (a->sackTimerRunning) {
457 			untimeout(ng_pptpgre_send_ack_timeout,
458 				node, a->sackTimer);
459 			a->sackTimerRunning = 0;
460 		}
461 	}
462 
463 	/* Prepend GRE header to outgoing frame */
464 	grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
465 	if (m == NULL) {
466 		MGETHDR(m, M_DONTWAIT, MT_DATA);
467 		if (m == NULL) {
468 			NG_FREE_META(meta);
469 			return (ENOBUFS);
470 		}
471 		m->m_len = m->m_pkthdr.len = grelen;
472 		m->m_pkthdr.rcvif = NULL;
473 	} else {
474 		M_PREPEND(m, grelen, M_NOWAIT);
475 		if (m == NULL || (m->m_len < grelen
476 		    && (m = m_pullup(m, grelen)) == NULL)) {
477 			NG_FREE_META(meta);
478 			return (ENOBUFS);
479 		}
480 	}
481 	bcopy(gre, mtod(m, u_char *), grelen);
482 
483 	/* Deliver packet */
484 	NG_SEND_DATA(error, priv->lower, m, meta);
485 	return (error);
486 }
487 
488 /*
489  * Handle an incoming packet.  The packet includes the IP header.
490  */
491 static int
492 ng_pptpgre_recv(node_p node, struct mbuf *m, meta_p meta)
493 {
494 	const priv_p priv = node->private;
495 	int iphlen, grelen, extralen;
496 	struct greheader *gre;
497 	struct ip *ip;
498 	int error = 0;
499 
500 	/* Sanity check packet length */
501 	if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) {
502 bad:
503 		NG_FREE_DATA(m, meta);
504 		return (EINVAL);
505 	}
506 
507 	/* Safely pull up the complete IP+GRE headers */
508 	if (m->m_len < sizeof(*ip) + sizeof(*gre)
509 	    && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) {
510 		NG_FREE_META(meta);
511 		return (ENOBUFS);
512 	}
513 	ip = mtod(m, struct ip *);
514 	iphlen = ip->ip_hl << 2;
515 	if (m->m_len < iphlen + sizeof(*gre)) {
516 		if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) {
517 			NG_FREE_META(meta);
518 			return (ENOBUFS);
519 		}
520 		ip = mtod(m, struct ip *);
521 	}
522 	gre = (struct greheader *)((u_char *)ip + iphlen);
523 	grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
524 	if (m->m_pkthdr.len < iphlen + grelen)
525 		goto bad;
526 	if (m->m_len < iphlen + grelen) {
527 		if ((m = m_pullup(m, iphlen + grelen)) == NULL) {
528 			NG_FREE_META(meta);
529 			return (ENOBUFS);
530 		}
531 		ip = mtod(m, struct ip *);
532 		gre = (struct greheader *)((u_char *)ip + iphlen);
533 	}
534 
535 	/* Sanity check packet length and GRE header bits */
536 	extralen = m->m_pkthdr.len
537 	    - (iphlen + grelen + (u_int16_t)ntohs(gre->length));
538 	if (extralen < 0)
539 		goto bad;
540 	if ((ntohl(*((u_int32_t *)gre)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE)
541 		goto bad;
542 	if (ntohs(gre->cid) != priv->conf.cid)
543 		goto bad;
544 
545 	/* Look for peer ack */
546 	if (gre->hasAck) {
547 		struct ng_pptpgre_ackp *const a = &priv->ackp;
548 		const u_int32_t	ack = ntohl(gre->data[gre->hasSeq]);
549 		const int index = ack - priv->recvAck - 1;
550 		const long sample = ng_pptpgre_time(node) - a->timeSent[index];
551 		long diff;
552 
553 		/* Sanity check ack value */
554 		if (ack <= priv->recvAck)	/* ack already timed out */
555 			goto bad;
556 		if (ack > priv->xmitSeq)	/* we never sent it! */
557 			goto bad;
558 		priv->recvAck = ack;
559 
560 		/* Update adaptive timeout stuff */
561 		diff = sample - a->rtt;
562 		a->rtt += PPTP_ACK_ALPHA(diff);
563 		if (diff < 0)
564 			diff = -diff;
565 		a->dev += PPTP_ACK_BETA(diff - a->dev);
566 		a->ato = a->rtt + (u_int) (PPTP_ACK_CHI(a->dev));
567 		if (a->ato > PPTP_MAX_TIMEOUT)
568 			a->ato = PPTP_MAX_TIMEOUT;
569 		ovbcopy(a->timeSent + index + 1, a->timeSent,
570 		    sizeof(*a->timeSent) * (PPTP_XMIT_WIN - (index + 1)));
571 		if (ack >= a->winAck && a->xmitWin < PPTP_XMIT_WIN) {
572 			a->xmitWin++;
573 			a->winAck = ack + a->xmitWin;
574 		}
575 
576 		/* (Re)start receive ACK timer as necessary */
577 		ng_pptpgre_start_recv_ack_timer(node);
578 	}
579 
580 	/* See if frame contains any data */
581 	if (gre->hasSeq) {
582 		struct ng_pptpgre_ackp *const a = &priv->ackp;
583 		const u_int32_t seq = ntohl(gre->data[0]);
584 
585 		/* Sanity check sequence number */
586 		if (seq <= priv->recvSeq)	/* out-of-order or dup */
587 			goto bad;
588 		priv->recvSeq = seq;
589 
590 		/* We need to acknowledge this packet; do it soon... */
591 		if (!a->sackTimerRunning) {
592 			long ackTimeout;
593 
594 			/* Take half of the estimated round trip time */
595 			ackTimeout = (a->rtt >> 1);
596 
597 			/* If too soon, just send one right now */
598 			if (!priv->conf.enableDelayedAck)
599 				ng_pptpgre_xmit(node, NULL, NULL);
600 			else {			/* send the ack later */
601 				if (ackTimeout > PPTP_MAX_ACK_DELAY)
602 					ackTimeout = PPTP_MAX_ACK_DELAY;
603 				a->sackTimer = timeout(
604 				    ng_pptpgre_send_ack_timeout, node,
605 				    ackTimeout * hz / PPTP_TIME_SCALE);
606 				a->sackTimerRunning = 1;
607 			}
608 		}
609 
610 		/* Trim mbuf down to internal payload */
611 		m_adj(m, iphlen + grelen);
612 		if (extralen > 0)
613 			m_adj(m, -extralen);
614 
615 		/* Deliver frame to upper layers */
616 		NG_SEND_DATA(error, priv->upper, m, meta);
617 	} else
618 		NG_FREE_DATA(m, meta);		/* no data to deliver */
619 	return (error);
620 }
621 
622 /*************************************************************************
623 		    TIMER RELATED FUNCTIONS
624 *************************************************************************/
625 
626 /*
627  * Set a timer for the peer's acknowledging our oldest unacknowledged
628  * sequence number.  If we get an ack for this sequence number before
629  * the timer goes off, we cancel the timer.  Resets currently running
630  * recv ack timer, if any.
631  */
632 static void
633 ng_pptpgre_start_recv_ack_timer(node_p node)
634 {
635 	const priv_p priv = node->private;
636 	struct ng_pptpgre_ackp *const a = &priv->ackp;
637 	int remain;
638 
639 	/* Stop current recv ack timer, if any */
640 	untimeout(ng_pptpgre_recv_ack_timeout, node, a->rackTimer);
641 	if (priv->recvAck == priv->xmitSeq)
642 		return;
643 
644 	/* Compute how long until oldest unack'd packet times out,
645 	   and reset the timer to that time. */
646 	remain = (a->timeSent[0] + a->ato) - ng_pptpgre_time(node);
647 	if (remain < 0)
648 		remain = 0;
649 	a->rackTimer = timeout(ng_pptpgre_recv_ack_timeout,
650 	    node, remain * hz / PPTP_TIME_SCALE);
651 }
652 
653 /*
654  * The peer has failed to acknowledge the oldest unacknowledged sequence
655  * number within the time allotted.  Update our adaptive timeout parameters
656  * and reset/restart the recv ack timer.
657  */
658 static void
659 ng_pptpgre_recv_ack_timeout(void *arg)
660 {
661 	const node_p node = arg;
662 	const priv_p priv = node->private;
663 	struct ng_pptpgre_ackp *const a = &priv->ackp;
664 
665 	/* Update adaptive timeout stuff */
666 	a->rtt = PPTP_ACK_DELTA(a->rtt);
667 	a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
668 	if (a->ato > PPTP_MAX_TIMEOUT)
669 		a->ato = PPTP_MAX_TIMEOUT;
670 	priv->recvAck++;			/* assume packet was lost */
671 	a->winAck = priv->recvAck + a->xmitWin;	/* reset win expand time */
672 	ovbcopy(a->timeSent + 1, a->timeSent,	/* shift xmit window times */
673 	    sizeof(*a->timeSent) * (PPTP_XMIT_WIN - 1));
674 	a->xmitWin = (a->xmitWin + 1) / 2;	/* shrink transmit window */
675 
676 	/* Restart timer if there are any more outstanding frames */
677 	if (priv->recvAck != priv->xmitSeq)
678 		ng_pptpgre_start_recv_ack_timer(node);
679 }
680 
681 /*
682  * We've waited as long as we're willing to wait before sending an
683  * acknowledgement to the peer for received frames. We had hoped to
684  * be able to piggy back our acknowledgement on an outgoing data frame,
685  * but apparently there haven't been any since. So send the ack now.
686  */
687 static void
688 ng_pptpgre_send_ack_timeout(void *arg)
689 {
690 	const node_p node = arg;
691 	const priv_p priv = node->private;
692 	struct ng_pptpgre_ackp *const a = &priv->ackp;
693 
694 	/* Send a frame with an ack but no payload */
695 	a->sackTimerRunning = 0;
696   	ng_pptpgre_xmit(node, NULL, NULL);
697 }
698 
699 /*************************************************************************
700 		    MISC FUNCTIONS
701 *************************************************************************/
702 
703 /*
704  * Reset state
705  */
706 static void
707 ng_pptpgre_reset(node_p node)
708 {
709 	const priv_p priv = node->private;
710 	struct ng_pptpgre_ackp *const a = &priv->ackp;
711 
712 	/* Reset adaptive timeout state */
713 	a->ato = PPTP_MAX_TIMEOUT;
714 	a->rtt = priv->conf.peerPpd * PPTP_TIME_SCALE / 10;  /* ppd in 10ths */
715 	if (a->rtt < PPTP_MIN_RTT)
716 		a->rtt = PPTP_MIN_RTT;
717 	a->dev = 0;
718 	a->xmitWin = (priv->conf.recvWin + 1) / 2;
719 	if (a->xmitWin < 1)
720 		a->xmitWin = 1;
721 	if (a->xmitWin > PPTP_XMIT_WIN)
722 		a->xmitWin = PPTP_XMIT_WIN;
723 	a->winAck = a->xmitWin;
724 
725 	/* Reset sequence numbers */
726 	priv->recvSeq = 0;
727 	priv->recvAck = 0;
728 	priv->xmitSeq = 0;
729 	priv->xmitAck = 0;
730 
731 	/* Reset start time */
732 	getmicrotime(&priv->startTime);
733 
734 	/* Stop timers */
735 	untimeout(ng_pptpgre_send_ack_timeout, node, a->sackTimer);
736 	untimeout(ng_pptpgre_recv_ack_timeout, node, a->rackTimer);
737 	a->sackTimerRunning = 0;
738 }
739 
740 /*
741  * Return the current time scaled & translated to our internally used format.
742  */
743 static pptptime_t
744 ng_pptpgre_time(node_p node)
745 {
746 	const priv_p priv = node->private;
747 	struct timeval tv;
748 
749 	getmicrotime(&tv);
750 	if (tv.tv_sec < priv->startTime.tv_sec
751 	    || (tv.tv_sec == priv->startTime.tv_sec
752 	      && tv.tv_usec < priv->startTime.tv_usec))
753 		return (0);
754 	timevalsub(&tv, &priv->startTime);
755 	tv.tv_sec *= PPTP_TIME_SCALE;
756 	tv.tv_usec /= 1000000 / PPTP_TIME_SCALE;
757 	return(tv.tv_sec + tv.tv_usec);
758 }
759 
760