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