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