xref: /freebsd/sys/netgraph/ng_pptpgre.c (revision 23f282aa31e9b6fceacd449020e936e98d6f2298)
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
119 typedef u_int32_t		pptptime_t;
120 
121 /* Acknowledgment timeout parameters and functions */
122 #define PPTP_XMIT_WIN		8			/* max xmit window */
123 #define PPTP_MIN_RTT		(PPTP_TIME_SCALE / 10)	/* 1/10 second */
124 #define PPTP_MAX_TIMEOUT	(10 * PPTP_TIME_SCALE)	/* 10 seconds */
125 
126 #define PPTP_ACK_ALPHA(x)	((x) >> 3)	/* alpha = 0.125 */
127 #define PPTP_ACK_BETA(x)	((x) >> 2)	/* beta = 0.25 */
128 #define PPTP_ACK_CHI(x) 	((x) << 2)	/* chi = 4 */
129 #define PPTP_ACK_DELTA(x) 	((x) << 1)	/* delta = 2 */
130 
131 /* We keep packet retransmit and acknowlegement state in this struct */
132 struct ng_pptpgre_ackp {
133 	int32_t			ato;		/* adaptive time-out value */
134 	int32_t			rtt;		/* round trip time estimate */
135 	int32_t			dev;		/* deviation estimate */
136 	u_int16_t		xmitWin;	/* size of xmit window */
137 	u_char			sackTimerRunning;/* send ack timer is running */
138 	u_int32_t		winAck;		/* seq when xmitWin will grow */
139 	struct callout_handle	sackTimer;	/* send ack timer */
140 	struct callout_handle	rackTimer;	/* recv ack timer */
141 	pptptime_t		timeSent[PPTP_XMIT_WIN];
142 };
143 
144 /* When we recieve a packet, we wait to see if there's an outgoing packet
145    we can piggy-back the ACK off of.  These parameters determine the mimimum
146    and maxmimum length of time we're willing to wait in order to do that. */
147 #define PPTP_MAX_ACK_DELAY	((int) (0.25 * PPTP_TIME_SCALE))
148 
149 /* Node private data */
150 struct ng_pptpgre_private {
151 	hook_p			upper;		/* hook to upper layers */
152 	hook_p			lower;		/* hook to lower layers */
153 	struct ng_pptpgre_conf	conf;		/* configuration info */
154 	struct ng_pptpgre_ackp	ackp;		/* packet transmit ack state */
155 	u_int32_t		recvSeq;	/* last seq # we rcv'd */
156 	u_int32_t		xmitSeq;	/* last seq # we sent */
157 	u_int32_t		recvAck;	/* last seq # peer ack'd */
158 	u_int32_t		xmitAck;	/* last seq # we ack'd */
159 	struct timeval		startTime;	/* time node was created */
160 };
161 typedef struct ng_pptpgre_private *priv_p;
162 
163 /* Netgraph node methods */
164 static ng_constructor_t	ng_pptpgre_constructor;
165 static ng_rcvmsg_t	ng_pptpgre_rcvmsg;
166 static ng_shutdown_t	ng_pptpgre_rmnode;
167 static ng_newhook_t	ng_pptpgre_newhook;
168 static ng_rcvdata_t	ng_pptpgre_rcvdata;
169 static ng_disconnect_t	ng_pptpgre_disconnect;
170 
171 /* Helper functions */
172 static int	ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta);
173 static int	ng_pptpgre_recv(node_p node, struct mbuf *m, meta_p meta);
174 static void	ng_pptpgre_start_recv_ack_timer(node_p node);
175 static void	ng_pptpgre_recv_ack_timeout(void *arg);
176 static void	ng_pptpgre_send_ack_timeout(void *arg);
177 static void	ng_pptpgre_reset(node_p node);
178 static pptptime_t ng_pptpgre_time(node_p node);
179 
180 /* Parse type for struct ng_pptpgre_conf */
181 static const struct ng_parse_struct_info
182 	ng_pptpgre_conf_type_info = NG_PPTPGRE_CONF_TYPE_INFO;
183 static const struct ng_parse_type ng_pptpgre_conf_type = {
184 	&ng_parse_struct_type,
185 	&ng_pptpgre_conf_type_info,
186 };
187 
188 /* List of commands and how to convert arguments to/from ASCII */
189 static const struct ng_cmdlist ng_pptpgre_cmdlist[] = {
190 	{
191 	  NGM_PPTPGRE_COOKIE,
192 	  NGM_PPTPGRE_SET_CONFIG,
193 	  "setconfig",
194 	  &ng_pptpgre_conf_type,
195 	  NULL
196 	},
197 	{
198 	  NGM_PPTPGRE_COOKIE,
199 	  NGM_PPTPGRE_GET_CONFIG,
200 	  "getconfig",
201 	  NULL,
202 	  &ng_pptpgre_conf_type
203 	},
204 	{ 0 }
205 };
206 
207 /* Node type descriptor */
208 static struct ng_type ng_pptpgre_typestruct = {
209 	NG_VERSION,
210 	NG_PPTPGRE_NODE_TYPE,
211 	NULL,
212 	ng_pptpgre_constructor,
213 	ng_pptpgre_rcvmsg,
214 	ng_pptpgre_rmnode,
215 	ng_pptpgre_newhook,
216 	NULL,
217 	NULL,
218 	ng_pptpgre_rcvdata,
219 	ng_pptpgre_rcvdata,
220 	ng_pptpgre_disconnect,
221 	ng_pptpgre_cmdlist
222 };
223 NETGRAPH_INIT(pptpgre, &ng_pptpgre_typestruct);
224 
225 #define ERROUT(x)	do { error = (x); goto done; } while (0)
226 
227 /************************************************************************
228 			NETGRAPH NODE STUFF
229  ************************************************************************/
230 
231 /*
232  * Node type constructor
233  */
234 static int
235 ng_pptpgre_constructor(node_p *nodep)
236 {
237 	priv_p priv;
238 	int error;
239 
240 	/* Allocate private structure */
241 	MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK);
242 	if (priv == NULL)
243 		return (ENOMEM);
244 	bzero(priv, sizeof(*priv));
245 
246 	/* Call generic node constructor */
247 	if ((error = ng_make_node_common(&ng_pptpgre_typestruct, nodep))) {
248 		FREE(priv, M_NETGRAPH);
249 		return (error);
250 	}
251 	(*nodep)->private = priv;
252 
253 	/* Initialize state */
254 	callout_handle_init(&priv->ackp.sackTimer);
255 	callout_handle_init(&priv->ackp.rackTimer);
256 
257 	/* Done */
258 	return (0);
259 }
260 
261 /*
262  * Give our OK for a hook to be added.
263  */
264 static int
265 ng_pptpgre_newhook(node_p node, hook_p hook, const char *name)
266 {
267 	const priv_p priv = node->private;
268 	hook_p *hookPtr;
269 
270 	/* Check hook name */
271 	if (strcmp(name, NG_PPTPGRE_HOOK_UPPER) == 0)
272 		hookPtr = &priv->upper;
273 	else if (strcmp(name, NG_PPTPGRE_HOOK_LOWER) == 0)
274 		hookPtr = &priv->lower;
275 	else
276 		return (EINVAL);
277 
278 	/* See if already connected */
279 	if (*hookPtr != NULL)
280 		return (EISCONN);
281 
282 	/* OK */
283 	*hookPtr = hook;
284 	return (0);
285 }
286 
287 /*
288  * Receive a control message.
289  */
290 static int
291 ng_pptpgre_rcvmsg(node_p node, struct ng_mesg *msg,
292 	      const char *raddr, struct ng_mesg **rptr, hook_p lasthook)
293 {
294 	const priv_p priv = node->private;
295 	struct ng_mesg *resp = NULL;
296 	int error = 0;
297 
298 	switch (msg->header.typecookie) {
299 	case NGM_PPTPGRE_COOKIE:
300 		switch (msg->header.cmd) {
301 		case NGM_PPTPGRE_SET_CONFIG:
302 		    {
303 			struct ng_pptpgre_conf *const newConf =
304 				(struct ng_pptpgre_conf *) msg->data;
305 
306 			/* Check for invalid or illegal config */
307 			if (msg->header.arglen != sizeof(*newConf))
308 				ERROUT(EINVAL);
309 			ng_pptpgre_reset(node);		/* reset on configure */
310 			priv->conf = *newConf;
311 			break;
312 		    }
313 		case NGM_PPTPGRE_GET_CONFIG:
314 			NG_MKRESPONSE(resp, msg, sizeof(priv->conf), M_NOWAIT);
315 			if (resp == NULL)
316 				ERROUT(ENOMEM);
317 			bcopy(&priv->conf, resp->data, sizeof(priv->conf));
318 			break;
319 		default:
320 			error = EINVAL;
321 			break;
322 		}
323 		break;
324 	default:
325 		error = EINVAL;
326 		break;
327 	}
328 	if (rptr)
329 		*rptr = resp;
330 	else if (resp)
331 		FREE(resp, M_NETGRAPH);
332 
333 done:
334 	FREE(msg, M_NETGRAPH);
335 	return (error);
336 }
337 
338 /*
339  * Receive incoming data on a hook.
340  */
341 static int
342 ng_pptpgre_rcvdata(hook_p hook, struct mbuf *m, meta_p meta,
343 		struct mbuf **ret_m, meta_p *ret_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 	int s = splnet();
662 	const node_p node = arg;
663 	const priv_p priv = node->private;
664 	struct ng_pptpgre_ackp *const a = &priv->ackp;
665 
666 	/* Update adaptive timeout stuff */
667 	a->rtt = PPTP_ACK_DELTA(a->rtt);
668 	a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
669 	if (a->ato > PPTP_MAX_TIMEOUT)
670 		a->ato = PPTP_MAX_TIMEOUT;
671 	priv->recvAck++;			/* assume packet was lost */
672 	a->winAck = priv->recvAck + a->xmitWin;	/* reset win expand time */
673 	ovbcopy(a->timeSent + 1, a->timeSent,	/* shift xmit window times */
674 	    sizeof(*a->timeSent) * (PPTP_XMIT_WIN - 1));
675 	a->xmitWin = (a->xmitWin + 1) / 2;	/* shrink transmit window */
676 
677 	/* Restart timer if there are any more outstanding frames */
678 	if (priv->recvAck != priv->xmitSeq)
679 		ng_pptpgre_start_recv_ack_timer(node);
680 	splx(s);
681 }
682 
683 /*
684  * We've waited as long as we're willing to wait before sending an
685  * acknowledgement to the peer for received frames. We had hoped to
686  * be able to piggy back our acknowledgement on an outgoing data frame,
687  * but apparently there haven't been any since. So send the ack now.
688  */
689 static void
690 ng_pptpgre_send_ack_timeout(void *arg)
691 {
692 	int s = splnet();
693 	const node_p node = arg;
694 	const priv_p priv = node->private;
695 	struct ng_pptpgre_ackp *const a = &priv->ackp;
696 
697 	/* Send a frame with an ack but no payload */
698 	a->sackTimerRunning = 0;
699   	ng_pptpgre_xmit(node, NULL, NULL);
700 	splx(s);
701 }
702 
703 /*************************************************************************
704 		    MISC FUNCTIONS
705 *************************************************************************/
706 
707 /*
708  * Reset state
709  */
710 static void
711 ng_pptpgre_reset(node_p node)
712 {
713 	const priv_p priv = node->private;
714 	struct ng_pptpgre_ackp *const a = &priv->ackp;
715 
716 	/* Reset adaptive timeout state */
717 	a->ato = PPTP_MAX_TIMEOUT;
718 	a->rtt = priv->conf.peerPpd * PPTP_TIME_SCALE / 10;  /* ppd in 10ths */
719 	if (a->rtt < PPTP_MIN_RTT)
720 		a->rtt = PPTP_MIN_RTT;
721 	a->dev = 0;
722 	a->xmitWin = (priv->conf.recvWin + 1) / 2;
723 	if (a->xmitWin < 1)
724 		a->xmitWin = 1;
725 	if (a->xmitWin > PPTP_XMIT_WIN)
726 		a->xmitWin = PPTP_XMIT_WIN;
727 	a->winAck = a->xmitWin;
728 
729 	/* Reset sequence numbers */
730 	priv->recvSeq = 0;
731 	priv->recvAck = 0;
732 	priv->xmitSeq = 0;
733 	priv->xmitAck = 0;
734 
735 	/* Reset start time */
736 	getmicrotime(&priv->startTime);
737 
738 	/* Stop timers */
739 	untimeout(ng_pptpgre_send_ack_timeout, node, a->sackTimer);
740 	untimeout(ng_pptpgre_recv_ack_timeout, node, a->rackTimer);
741 	a->sackTimerRunning = 0;
742 }
743 
744 /*
745  * Return the current time scaled & translated to our internally used format.
746  */
747 static pptptime_t
748 ng_pptpgre_time(node_p node)
749 {
750 	const priv_p priv = node->private;
751 	struct timeval tv;
752 
753 	getmicrotime(&tv);
754 	if (tv.tv_sec < priv->startTime.tv_sec
755 	    || (tv.tv_sec == priv->startTime.tv_sec
756 	      && tv.tv_usec < priv->startTime.tv_usec))
757 		return (0);
758 	timevalsub(&tv, &priv->startTime);
759 	tv.tv_sec *= PPTP_TIME_SCALE;
760 	tv.tv_usec /= 1000000 / PPTP_TIME_SCALE;
761 	return(tv.tv_sec + tv.tv_usec);
762 }
763 
764