xref: /freebsd/sys/netgraph/ng_pptpgre.c (revision 71fe318b852b8dfb3e799cb12ef184750f7f8eac)
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	(10 * PPTP_TIME_SCALE)	/* 10 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 	node_p			*sackTimerPtr;	/* send ack timer pointer */
148 	node_p			*rackTimerPtr;	/* recv ack timer pointer */
149 	u_int32_t		winAck;		/* seq when xmitWin will grow */
150 	pptptime_t		timeSent[PPTP_XMIT_WIN];
151 #ifdef DEBUG_RAT
152 	pptptime_t		timerStart;	/* when rackTimer started */
153 	pptptime_t		timerLength;	/* rackTimer duration */
154 #endif
155 };
156 
157 /* Node private data */
158 struct ng_pptpgre_private {
159 	hook_p			upper;		/* hook to upper layers */
160 	hook_p			lower;		/* hook to lower layers */
161 	struct ng_pptpgre_conf	conf;		/* configuration info */
162 	struct ng_pptpgre_ackp	ackp;		/* packet transmit ack state */
163 	u_int32_t		recvSeq;	/* last seq # we rcv'd */
164 	u_int32_t		xmitSeq;	/* last seq # we sent */
165 	u_int32_t		recvAck;	/* last seq # peer ack'd */
166 	u_int32_t		xmitAck;	/* last seq # we ack'd */
167 	u_int			timers;		/* number of pending timers */
168 	struct timeval		startTime;	/* time node was created */
169 	struct ng_pptpgre_stats	stats;		/* node statistics */
170 };
171 typedef struct ng_pptpgre_private *priv_p;
172 
173 /* Netgraph node methods */
174 static ng_constructor_t	ng_pptpgre_constructor;
175 static ng_rcvmsg_t	ng_pptpgre_rcvmsg;
176 static ng_shutdown_t	ng_pptpgre_shutdown;
177 static ng_newhook_t	ng_pptpgre_newhook;
178 static ng_rcvdata_t	ng_pptpgre_rcvdata;
179 static ng_disconnect_t	ng_pptpgre_disconnect;
180 
181 /* Helper functions */
182 static int	ng_pptpgre_xmit(node_p node, item_p item);
183 static int	ng_pptpgre_recv(node_p node, item_p item);
184 static void	ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout);
185 static void	ng_pptpgre_stop_send_ack_timer(node_p node);
186 static void	ng_pptpgre_start_recv_ack_timer(node_p node);
187 static void	ng_pptpgre_stop_recv_ack_timer(node_p node);
188 static void	ng_pptpgre_recv_ack_timeout(void *arg);
189 static void	ng_pptpgre_send_ack_timeout(void *arg);
190 static void	ng_pptpgre_reset(node_p node);
191 static pptptime_t ng_pptpgre_time(node_p node);
192 
193 /* Parse type for struct ng_pptpgre_conf */
194 static const struct ng_parse_struct_field ng_pptpgre_conf_type_fields[]
195 	= NG_PPTPGRE_CONF_TYPE_INFO;
196 static const struct ng_parse_type ng_pptpgre_conf_type = {
197 	&ng_parse_struct_type,
198 	&ng_pptpgre_conf_type_fields,
199 };
200 
201 /* Parse type for struct ng_pptpgre_stats */
202 static const struct ng_parse_struct_field ng_pptpgre_stats_type_fields[]
203 	= NG_PPTPGRE_STATS_TYPE_INFO;
204 static const struct ng_parse_type ng_pptp_stats_type = {
205 	&ng_parse_struct_type,
206 	&ng_pptpgre_stats_type_fields
207 };
208 
209 /* List of commands and how to convert arguments to/from ASCII */
210 static const struct ng_cmdlist ng_pptpgre_cmdlist[] = {
211 	{
212 	  NGM_PPTPGRE_COOKIE,
213 	  NGM_PPTPGRE_SET_CONFIG,
214 	  "setconfig",
215 	  &ng_pptpgre_conf_type,
216 	  NULL
217 	},
218 	{
219 	  NGM_PPTPGRE_COOKIE,
220 	  NGM_PPTPGRE_GET_CONFIG,
221 	  "getconfig",
222 	  NULL,
223 	  &ng_pptpgre_conf_type
224 	},
225 	{
226 	  NGM_PPTPGRE_COOKIE,
227 	  NGM_PPTPGRE_GET_STATS,
228 	  "getstats",
229 	  NULL,
230 	  &ng_pptp_stats_type
231 	},
232 	{
233 	  NGM_PPTPGRE_COOKIE,
234 	  NGM_PPTPGRE_CLR_STATS,
235 	  "clrstats",
236 	  NULL,
237 	  NULL
238 	},
239 	{
240 	  NGM_PPTPGRE_COOKIE,
241 	  NGM_PPTPGRE_GETCLR_STATS,
242 	  "getclrstats",
243 	  NULL,
244 	  &ng_pptp_stats_type
245 	},
246 	{ 0 }
247 };
248 
249 /* Node type descriptor */
250 static struct ng_type ng_pptpgre_typestruct = {
251 	NG_ABI_VERSION,
252 	NG_PPTPGRE_NODE_TYPE,
253 	NULL,
254 	ng_pptpgre_constructor,
255 	ng_pptpgre_rcvmsg,
256 	ng_pptpgre_shutdown,
257 	ng_pptpgre_newhook,
258 	NULL,
259 	NULL,
260 	ng_pptpgre_rcvdata,
261 	ng_pptpgre_disconnect,
262 	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 	callout_init(&priv->ackp.sackTimer, 0);
289 	callout_init(&priv->ackp.rackTimer, 0);
290 
291 	/* Done */
292 	return (0);
293 }
294 
295 /*
296  * Give our OK for a hook to be added.
297  */
298 static int
299 ng_pptpgre_newhook(node_p node, hook_p hook, const char *name)
300 {
301 	const priv_p priv = NG_NODE_PRIVATE(node);
302 	hook_p *hookPtr;
303 
304 	/* Check hook name */
305 	if (strcmp(name, NG_PPTPGRE_HOOK_UPPER) == 0)
306 		hookPtr = &priv->upper;
307 	else if (strcmp(name, NG_PPTPGRE_HOOK_LOWER) == 0)
308 		hookPtr = &priv->lower;
309 	else
310 		return (EINVAL);
311 
312 	/* See if already connected */
313 	if (*hookPtr != NULL)
314 		return (EISCONN);
315 
316 	/* OK */
317 	*hookPtr = hook;
318 	return (0);
319 }
320 
321 /*
322  * Receive a control message.
323  */
324 static int
325 ng_pptpgre_rcvmsg(node_p node, item_p item, hook_p lasthook)
326 {
327 	const priv_p priv = NG_NODE_PRIVATE(node);
328 	struct ng_mesg *resp = NULL;
329 	int error = 0;
330 	struct ng_mesg *msg;
331 
332 	NGI_GET_MSG(item, msg);
333 	switch (msg->header.typecookie) {
334 	case NGM_PPTPGRE_COOKIE:
335 		switch (msg->header.cmd) {
336 		case NGM_PPTPGRE_SET_CONFIG:
337 		    {
338 			struct ng_pptpgre_conf *const newConf =
339 				(struct ng_pptpgre_conf *) msg->data;
340 
341 			/* Check for invalid or illegal config */
342 			if (msg->header.arglen != sizeof(*newConf))
343 				ERROUT(EINVAL);
344 			ng_pptpgre_reset(node);		/* reset on configure */
345 			priv->conf = *newConf;
346 			break;
347 		    }
348 		case NGM_PPTPGRE_GET_CONFIG:
349 			NG_MKRESPONSE(resp, msg, sizeof(priv->conf), M_NOWAIT);
350 			if (resp == NULL)
351 				ERROUT(ENOMEM);
352 			bcopy(&priv->conf, resp->data, sizeof(priv->conf));
353 			break;
354 		case NGM_PPTPGRE_GET_STATS:
355 		case NGM_PPTPGRE_CLR_STATS:
356 		case NGM_PPTPGRE_GETCLR_STATS:
357 		    {
358 			if (msg->header.cmd != NGM_PPTPGRE_CLR_STATS) {
359 				NG_MKRESPONSE(resp, msg,
360 				    sizeof(priv->stats), M_NOWAIT);
361 				if (resp == NULL)
362 					ERROUT(ENOMEM);
363 				bcopy(&priv->stats,
364 				    resp->data, sizeof(priv->stats));
365 			}
366 			if (msg->header.cmd != NGM_PPTPGRE_GET_STATS)
367 				bzero(&priv->stats, sizeof(priv->stats));
368 			break;
369 		    }
370 		default:
371 			error = EINVAL;
372 			break;
373 		}
374 		break;
375 	default:
376 		error = EINVAL;
377 		break;
378 	}
379 done:
380 	NG_RESPOND_MSG(error, node, item, resp);
381 	NG_FREE_MSG(msg);
382 	return (error);
383 }
384 
385 /*
386  * Receive incoming data on a hook.
387  */
388 static int
389 ng_pptpgre_rcvdata(hook_p hook, item_p item)
390 {
391 	const node_p node = NG_HOOK_NODE(hook);
392 	const priv_p priv = NG_NODE_PRIVATE(node);
393 
394 	/* If not configured, reject */
395 	if (!priv->conf.enabled) {
396 		NG_FREE_ITEM(item);
397 		return (ENXIO);
398 	}
399 
400 	/* Treat as xmit or recv data */
401 	if (hook == priv->upper)
402 		return ng_pptpgre_xmit(node, item);
403 	if (hook == priv->lower)
404 		return ng_pptpgre_recv(node, item);
405 	panic("%s: weird hook", __func__);
406 }
407 
408 /*
409  * Destroy node
410  */
411 static int
412 ng_pptpgre_shutdown(node_p node)
413 {
414 	const priv_p priv = NG_NODE_PRIVATE(node);
415 
416 	/* Reset node */
417 	ng_pptpgre_reset(node);
418 
419 	/* If no timers remain, free private info as well */
420 	if (priv->timers == 0) {
421 		bzero(priv, sizeof(*priv));
422 		FREE(priv, M_NETGRAPH);
423 		NG_NODE_SET_PRIVATE(node, NULL);
424 	}
425 
426 	/* Decrement ref count */
427 	NG_NODE_UNREF(node);
428 	return (0);
429 }
430 
431 /*
432  * Hook disconnection
433  */
434 static int
435 ng_pptpgre_disconnect(hook_p hook)
436 {
437 	const node_p node = NG_HOOK_NODE(hook);
438 	const priv_p priv = NG_NODE_PRIVATE(node);
439 
440 	/* Zero out hook pointer */
441 	if (hook == priv->upper)
442 		priv->upper = NULL;
443 	else if (hook == priv->lower)
444 		priv->lower = NULL;
445 	else
446 		panic("%s: unknown hook", __func__);
447 
448 	/* Go away if no longer connected to anything */
449 	if ((NG_NODE_NUMHOOKS(node) == 0)
450 	&& (NG_NODE_IS_VALID(node)))
451 		ng_rmnode_self(node);
452 	return (0);
453 }
454 
455 /*************************************************************************
456 		    TRANSMIT AND RECEIVE FUNCTIONS
457 *************************************************************************/
458 
459 /*
460  * Transmit an outgoing frame, or just an ack if m is NULL.
461  */
462 static int
463 ng_pptpgre_xmit(node_p node, item_p item)
464 {
465 	const priv_p priv = NG_NODE_PRIVATE(node);
466 	struct ng_pptpgre_ackp *const a = &priv->ackp;
467 	u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)];
468 	struct greheader *const gre = (struct greheader *)buf;
469 	int grelen, error;
470 	struct mbuf *m;
471 
472 	if (item) {
473 		NGI_GET_M(item, m);
474 	} else {
475 		m = NULL;
476 	}
477 	/* Check if there's data */
478 	if (m != NULL) {
479 
480 		/* Is our transmit window full? */
481 		if ((u_int32_t)PPTP_SEQ_DIFF(priv->xmitSeq, priv->recvAck)
482 		      >= a->xmitWin) {
483 			priv->stats.xmitDrops++;
484 			NG_FREE_M(m);
485 			NG_FREE_ITEM(item);
486 			return (ENOBUFS);
487 		}
488 
489 		/* Sanity check frame length */
490 		if (m != NULL && m->m_pkthdr.len > PPTP_MAX_PAYLOAD) {
491 			priv->stats.xmitTooBig++;
492 			NG_FREE_M(m);
493 			NG_FREE_ITEM(item);
494 			return (EMSGSIZE);
495 		}
496 	} else {
497 		priv->stats.xmitLoneAcks++;
498 	}
499 
500 	/* Build GRE header */
501 	((u_int32_t *)gre)[0] = htonl(PPTP_INIT_VALUE);
502 	gre->length = (m != NULL) ? htons((u_short)m->m_pkthdr.len) : 0;
503 	gre->cid = htons(priv->conf.peerCid);
504 
505 	/* Include sequence number if packet contains any data */
506 	if (m != NULL) {
507 		gre->hasSeq = 1;
508 		a->timeSent[priv->xmitSeq - priv->recvAck]
509 		    = ng_pptpgre_time(node);
510 		priv->xmitSeq++;
511 		gre->data[0] = htonl(priv->xmitSeq);
512 	}
513 
514 	/* Include acknowledgement (and stop send ack timer) if needed */
515 	if (priv->conf.enableAlwaysAck || priv->xmitAck != priv->recvSeq) {
516 		gre->hasAck = 1;
517 		gre->data[gre->hasSeq] = htonl(priv->recvSeq);
518 		priv->xmitAck = priv->recvSeq;
519 		ng_pptpgre_stop_send_ack_timer(node);
520 	}
521 
522 	/* Prepend GRE header to outgoing frame */
523 	grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
524 	if (m == NULL) {
525 		MGETHDR(m, M_DONTWAIT, MT_DATA);
526 		if (m == NULL) {
527 			priv->stats.memoryFailures++;
528 			if (item)
529 				NG_FREE_ITEM(item);
530 			return (ENOBUFS);
531 		}
532 		m->m_len = m->m_pkthdr.len = grelen;
533 		m->m_pkthdr.rcvif = NULL;
534 	} else {
535 		M_PREPEND(m, grelen, M_NOWAIT);
536 		if (m == NULL || (m->m_len < grelen
537 		    && (m = m_pullup(m, grelen)) == NULL)) {
538 			priv->stats.memoryFailures++;
539 			if (item)
540 				NG_FREE_ITEM(item);
541 			return (ENOBUFS);
542 		}
543 	}
544 	bcopy(gre, mtod(m, u_char *), grelen);
545 
546 	/* Update stats */
547 	priv->stats.xmitPackets++;
548 	priv->stats.xmitOctets += m->m_pkthdr.len;
549 
550 	/* Deliver packet */
551 	if (item) {
552 		NG_FWD_NEW_DATA(error, item, priv->lower, m);
553 	} else {
554 		NG_SEND_DATA_ONLY(error, priv->lower, m);
555 	}
556 
557 
558 	/* Start receive ACK timer if data was sent and not already running */
559 	if (error == 0 && gre->hasSeq && priv->xmitSeq == priv->recvAck + 1)
560 		ng_pptpgre_start_recv_ack_timer(node);
561 	return (error);
562 }
563 
564 /*
565  * Handle an incoming packet.  The packet includes the IP header.
566  */
567 static int
568 ng_pptpgre_recv(node_p node, item_p item)
569 {
570 	const priv_p priv = NG_NODE_PRIVATE(node);
571 	int iphlen, grelen, extralen;
572 	const struct greheader *gre;
573 	const struct ip *ip;
574 	int error = 0;
575 	struct mbuf *m;
576 
577 	NGI_GET_M(item, m);
578 	/* Update stats */
579 	priv->stats.recvPackets++;
580 	priv->stats.recvOctets += m->m_pkthdr.len;
581 
582 	/* Sanity check packet length */
583 	if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) {
584 		priv->stats.recvRunts++;
585 bad:
586 		NG_FREE_M(m);
587 		NG_FREE_ITEM(item);
588 		return (EINVAL);
589 	}
590 
591 	/* Safely pull up the complete IP+GRE headers */
592 	if (m->m_len < sizeof(*ip) + sizeof(*gre)
593 	    && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) {
594 		priv->stats.memoryFailures++;
595 		NG_FREE_ITEM(item);
596 		return (ENOBUFS);
597 	}
598 	ip = mtod(m, const struct ip *);
599 	iphlen = ip->ip_hl << 2;
600 	if (m->m_len < iphlen + sizeof(*gre)) {
601 		if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) {
602 			priv->stats.memoryFailures++;
603 			NG_FREE_ITEM(item);
604 			return (ENOBUFS);
605 		}
606 		ip = mtod(m, const struct ip *);
607 	}
608 	gre = (const struct greheader *)((const u_char *)ip + iphlen);
609 	grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
610 	if (m->m_pkthdr.len < iphlen + grelen) {
611 		priv->stats.recvRunts++;
612 		goto bad;
613 	}
614 	if (m->m_len < iphlen + grelen) {
615 		if ((m = m_pullup(m, iphlen + grelen)) == NULL) {
616 			priv->stats.memoryFailures++;
617 			NG_FREE_ITEM(item);
618 			return (ENOBUFS);
619 		}
620 		ip = mtod(m, const struct ip *);
621 		gre = (const struct greheader *)((const u_char *)ip + iphlen);
622 	}
623 
624 	/* Sanity check packet length and GRE header bits */
625 	extralen = m->m_pkthdr.len
626 	    - (iphlen + grelen + gre->hasSeq * (u_int16_t)ntohs(gre->length));
627 	if (extralen < 0) {
628 		priv->stats.recvBadGRE++;
629 		goto bad;
630 	}
631 	if ((ntohl(*((const u_int32_t *)gre)) & PPTP_INIT_MASK)
632 	    != PPTP_INIT_VALUE) {
633 		priv->stats.recvBadGRE++;
634 		goto bad;
635 	}
636 	if (ntohs(gre->cid) != priv->conf.cid) {
637 		priv->stats.recvBadCID++;
638 		goto bad;
639 	}
640 
641 	/* Look for peer ack */
642 	if (gre->hasAck) {
643 		struct ng_pptpgre_ackp *const a = &priv->ackp;
644 		const u_int32_t	ack = ntohl(gre->data[gre->hasSeq]);
645 		const int index = ack - priv->recvAck - 1;
646 		long sample;
647 		long diff;
648 
649 		/* Sanity check ack value */
650 		if (PPTP_SEQ_DIFF(ack, priv->xmitSeq) > 0) {
651 			priv->stats.recvBadAcks++;
652 			goto badAck;		/* we never sent it! */
653 		}
654 		if (PPTP_SEQ_DIFF(ack, priv->recvAck) <= 0)
655 			goto badAck;		/* ack already timed out */
656 		priv->recvAck = ack;
657 
658 		/* Update adaptive timeout stuff */
659 		sample = ng_pptpgre_time(node) - a->timeSent[index];
660 		diff = sample - a->rtt;
661 		a->rtt += PPTP_ACK_ALPHA(diff);
662 		if (diff < 0)
663 			diff = -diff;
664 		a->dev += PPTP_ACK_BETA(diff - a->dev);
665 		a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
666 		if (a->ato > PPTP_MAX_TIMEOUT)
667 			a->ato = PPTP_MAX_TIMEOUT;
668 		if (a->ato < PPTP_MIN_TIMEOUT)
669 			a->ato = PPTP_MIN_TIMEOUT;
670 
671 		/* Shift packet transmit times in our transmit window */
672 		ovbcopy(a->timeSent + index + 1, a->timeSent,
673 		    sizeof(*a->timeSent) * (PPTP_XMIT_WIN - (index + 1)));
674 
675 		/* If we sent an entire window, increase window size by one */
676 		if (PPTP_SEQ_DIFF(ack, a->winAck) >= 0
677 		    && a->xmitWin < PPTP_XMIT_WIN) {
678 			a->xmitWin++;
679 			a->winAck = ack + a->xmitWin;
680 		}
681 
682 		/* Stop/(re)start receive ACK timer as necessary */
683 		ng_pptpgre_stop_recv_ack_timer(node);
684 		if (priv->recvAck != priv->xmitSeq)
685 			ng_pptpgre_start_recv_ack_timer(node);
686 	}
687 badAck:
688 
689 	/* See if frame contains any data */
690 	if (gre->hasSeq) {
691 		struct ng_pptpgre_ackp *const a = &priv->ackp;
692 		const u_int32_t seq = ntohl(gre->data[0]);
693 
694 		/* Sanity check sequence number */
695 		if (PPTP_SEQ_DIFF(seq, priv->recvSeq) <= 0) {
696 			if (seq == priv->recvSeq)
697 				priv->stats.recvDuplicates++;
698 			else
699 				priv->stats.recvOutOfOrder++;
700 			goto bad;		/* out-of-order or dup */
701 		}
702 		priv->recvSeq = seq;
703 
704 		/* We need to acknowledge this packet; do it soon... */
705 		if (a->sackTimerPtr == NULL) {
706 			int maxWait;
707 
708 			/* Take 1/4 of the estimated round trip time */
709 			maxWait = (a->rtt >> 2);
710 
711 			/* If delayed ACK is disabled, send it now */
712 			if (!priv->conf.enableDelayedAck)	/* ack now */
713 				ng_pptpgre_xmit(node, NULL);
714 			else {					/* ack later */
715 				if (maxWait < PPTP_MIN_ACK_DELAY)
716 					maxWait = PPTP_MIN_ACK_DELAY;
717 				if (maxWait > PPTP_MAX_ACK_DELAY)
718 					maxWait = PPTP_MAX_ACK_DELAY;
719 				ng_pptpgre_start_send_ack_timer(node, maxWait);
720 			}
721 		}
722 
723 		/* Trim mbuf down to internal payload */
724 		m_adj(m, iphlen + grelen);
725 		if (extralen > 0)
726 			m_adj(m, -extralen);
727 
728 		/* Deliver frame to upper layers */
729 		NG_FWD_NEW_DATA(error, item, priv->upper, m);
730 	} else {
731 		priv->stats.recvLoneAcks++;
732 		NG_FREE_ITEM(item);
733 		NG_FREE_M(m);		/* no data to deliver */
734 	}
735 	return (error);
736 }
737 
738 /*************************************************************************
739 		    TIMER RELATED FUNCTIONS
740 *************************************************************************/
741 
742 /*
743  * Start a timer for the peer's acknowledging our oldest unacknowledged
744  * sequence number.  If we get an ack for this sequence number before
745  * the timer goes off, we cancel the timer.  Resets currently running
746  * recv ack timer, if any.
747  */
748 static void
749 ng_pptpgre_start_recv_ack_timer(node_p node)
750 {
751 	const priv_p priv = NG_NODE_PRIVATE(node);
752 	struct ng_pptpgre_ackp *const a = &priv->ackp;
753 	int remain, ticks;
754 
755 	/* Compute how long until oldest unack'd packet times out,
756 	   and reset the timer to that time. */
757 	KASSERT(a->rackTimerPtr == NULL, ("%s: rackTimer", __func__));
758 	remain = (a->timeSent[0] + a->ato) - ng_pptpgre_time(node);
759 	if (remain < 0)
760 		remain = 0;
761 #ifdef DEBUG_RAT
762 	a->timerLength = remain;
763 	a->timerStart = ng_pptpgre_time(node);
764 #endif
765 
766 	/* Start new timer */
767 	MALLOC(a->rackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT);
768 	if (a->rackTimerPtr == NULL) {
769 		priv->stats.memoryFailures++;
770 		return;			/* XXX potential hang here */
771 	}
772 	*a->rackTimerPtr = node;	/* ensures the correct timeout event */
773 	NG_NODE_REF(node);
774 	priv->timers++;
775 
776 	/* Be conservative: timeout can happen up to 1 tick early */
777 	ticks = (((remain * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE) + 1;
778 	callout_reset(&a->rackTimer, ticks,
779 	    ng_pptpgre_recv_ack_timeout, a->rackTimerPtr);
780 }
781 
782 /*
783  * Stop receive ack timer.
784  */
785 static void
786 ng_pptpgre_stop_recv_ack_timer(node_p node)
787 {
788 	const priv_p priv = NG_NODE_PRIVATE(node);
789 	struct ng_pptpgre_ackp *const a = &priv->ackp;
790 
791 	if (callout_stop(&a->rackTimer)) {
792 		FREE(a->rackTimerPtr, M_NETGRAPH);
793 		priv->timers--;
794 		NG_NODE_UNREF(node);
795 	}
796 	a->rackTimerPtr = NULL;
797 }
798 
799 /*
800  * The peer has failed to acknowledge the oldest unacknowledged sequence
801  * number within the time allotted.  Update our adaptive timeout parameters
802  * and reset/restart the recv ack timer.
803  */
804 static void
805 ng_pptpgre_recv_ack_timeout(void *arg)
806 {
807 	int s = splnet();
808 	const node_p node = *((node_p *)arg);
809 	const priv_p priv = NG_NODE_PRIVATE(node);
810 	struct ng_pptpgre_ackp *const a = &priv->ackp;
811 
812 	/* This complicated stuff is needed to avoid race conditions */
813 	FREE(arg, M_NETGRAPH);
814 	KASSERT(node->nd_refs > 0, ("%s: no nd_refs", __func__));
815 	KASSERT(priv != NULL, ("%s: priv=NULL", __func__));
816 	priv->timers--;
817 	if (NG_NODE_NOT_VALID(node)) {	/* shutdown race condition */
818 		if (priv->timers == 0) {
819 			FREE(priv, M_NETGRAPH);
820 			NG_NODE_SET_PRIVATE(node, NULL);
821 		}
822 		NG_NODE_UNREF(node);
823 		splx(s);
824 		return;
825 	}
826 	if (arg != a->rackTimerPtr) {	/* timer stopped race condition */
827 		NG_NODE_UNREF(node);
828 		splx(s);
829 		return;
830 	}
831 	a->rackTimerPtr = NULL;
832 
833 	/* Update adaptive timeout stuff */
834 	priv->stats.recvAckTimeouts++;
835 	a->rtt = PPTP_ACK_DELTA(a->rtt);
836 	a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
837 	if (a->ato > PPTP_MAX_TIMEOUT)
838 		a->ato = PPTP_MAX_TIMEOUT;
839 	if (a->ato < PPTP_MIN_TIMEOUT)
840 		a->ato = PPTP_MIN_TIMEOUT;
841 
842 #ifdef DEBUG_RAT
843     log(LOG_DEBUG,
844 	"RAT now=%d seq=0x%x sent=%d tstart=%d tlen=%d ato=%d\n",
845 	(int)ng_pptpgre_time(node), priv->recvAck + 1,
846 	(int)a->timeSent[0], (int)a->timerStart, (int)a->timerLength, a->ato);
847 #endif
848 
849 	/* Reset ack and sliding window */
850 	priv->recvAck = priv->xmitSeq;		/* pretend we got the ack */
851 	a->xmitWin = (a->xmitWin + 1) / 2;	/* shrink transmit window */
852 	a->winAck = priv->recvAck + a->xmitWin;	/* reset win expand time */
853 	NG_NODE_UNREF(node);
854 	splx(s);
855 }
856 
857 /*
858  * Start the send ack timer. This assumes the timer is not
859  * already running.
860  */
861 static void
862 ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout)
863 {
864 	const priv_p priv = NG_NODE_PRIVATE(node);
865 	struct ng_pptpgre_ackp *const a = &priv->ackp;
866 	int ticks;
867 
868 	/* Start new timer */
869 	KASSERT(a->sackTimerPtr == NULL, ("%s: sackTimer", __func__));
870 	MALLOC(a->sackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT);
871 	if (a->sackTimerPtr == NULL) {
872 		priv->stats.memoryFailures++;
873 		return;			/* XXX potential hang here */
874 	}
875 	*a->sackTimerPtr = node;	/* ensures the correct timeout event */
876 	NG_NODE_REF(node);
877 	priv->timers++;
878 
879 	/* Be conservative: timeout can happen up to 1 tick early */
880 	ticks = (((ackTimeout * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE);
881 	callout_reset(&a->sackTimer, ticks,
882 	    ng_pptpgre_send_ack_timeout, a->sackTimerPtr);
883 }
884 
885 /*
886  * Stop send ack timer.
887  */
888 static void
889 ng_pptpgre_stop_send_ack_timer(node_p node)
890 {
891 	const priv_p priv = NG_NODE_PRIVATE(node);
892 	struct ng_pptpgre_ackp *const a = &priv->ackp;
893 
894 	if (callout_stop(&a->sackTimer)) {
895 		FREE(a->sackTimerPtr, M_NETGRAPH);
896 		priv->timers--;
897 		NG_NODE_UNREF(node);
898 	}
899 	a->sackTimerPtr = NULL;
900 }
901 
902 /*
903  * We've waited as long as we're willing to wait before sending an
904  * acknowledgement to the peer for received frames. We had hoped to
905  * be able to piggy back our acknowledgement on an outgoing data frame,
906  * but apparently there haven't been any since. So send the ack now.
907  */
908 static void
909 ng_pptpgre_send_ack_timeout(void *arg)
910 {
911 	int s = splnet();
912 	const node_p node = *((node_p *)arg);
913 	const priv_p priv = NG_NODE_PRIVATE(node);
914 	struct ng_pptpgre_ackp *const a = &priv->ackp;
915 
916 	/* This complicated stuff is needed to avoid race conditions */
917 	FREE(arg, M_NETGRAPH);
918 	KASSERT(node->nd_refs > 0, ("%s: no nd_refs", __func__));
919 	KASSERT(priv != NULL, ("%s: priv=NULL", __func__));
920 	priv->timers--;
921 	if (NG_NODE_NOT_VALID(node)) {	/* shutdown race condition */
922 		if (priv->timers == 0) {
923 			FREE(priv, M_NETGRAPH);
924 			NG_NODE_SET_PRIVATE(node, NULL);
925 		}
926 		NG_NODE_UNREF(node);
927 		splx(s);
928 		return;
929 	}
930 	if (a->sackTimerPtr != arg) {	/* timer stopped race condition */
931 		NG_NODE_UNREF(node);
932 		splx(s);
933 		return;
934 	}
935 	a->sackTimerPtr = NULL;
936 
937 	/* Send a frame with an ack but no payload */
938   	ng_pptpgre_xmit(node, NULL);
939 	NG_NODE_UNREF(node);
940 	splx(s);
941 }
942 
943 /*************************************************************************
944 		    MISC FUNCTIONS
945 *************************************************************************/
946 
947 /*
948  * Reset state
949  */
950 static void
951 ng_pptpgre_reset(node_p node)
952 {
953 	const priv_p priv = NG_NODE_PRIVATE(node);
954 	struct ng_pptpgre_ackp *const a = &priv->ackp;
955 
956 	/* Reset adaptive timeout state */
957 	a->ato = PPTP_MAX_TIMEOUT;
958 	a->rtt = priv->conf.peerPpd * PPTP_TIME_SCALE / 10;  /* ppd in 10ths */
959 	if (a->rtt < PPTP_MIN_RTT)
960 		a->rtt = PPTP_MIN_RTT;
961 	a->dev = 0;
962 	a->xmitWin = (priv->conf.recvWin + 1) / 2;
963 	if (a->xmitWin < 2)		/* often the first packet is lost */
964 		a->xmitWin = 2;		/*   because the peer isn't ready */
965 	if (a->xmitWin > PPTP_XMIT_WIN)
966 		a->xmitWin = PPTP_XMIT_WIN;
967 	a->winAck = a->xmitWin;
968 
969 	/* Reset sequence numbers */
970 	priv->recvSeq = ~0;
971 	priv->recvAck = ~0;
972 	priv->xmitSeq = ~0;
973 	priv->xmitAck = ~0;
974 
975 	/* Reset start time */
976 	getmicrouptime(&priv->startTime);
977 
978 	/* Reset stats */
979 	bzero(&priv->stats, sizeof(priv->stats));
980 
981 	/* Stop timers */
982 	ng_pptpgre_stop_send_ack_timer(node);
983 	ng_pptpgre_stop_recv_ack_timer(node);
984 }
985 
986 /*
987  * Return the current time scaled & translated to our internally used format.
988  */
989 static pptptime_t
990 ng_pptpgre_time(node_p node)
991 {
992 	const priv_p priv = NG_NODE_PRIVATE(node);
993 	struct timeval tv;
994 	pptptime_t t;
995 
996 	microuptime(&tv);
997 	if (tv.tv_sec < priv->startTime.tv_sec
998 	    || (tv.tv_sec == priv->startTime.tv_sec
999 	      && tv.tv_usec < priv->startTime.tv_usec))
1000 		return (0);
1001 	timevalsub(&tv, &priv->startTime);
1002 	t = (pptptime_t)tv.tv_sec * PPTP_TIME_SCALE;
1003 	t += (pptptime_t)tv.tv_usec / (1000000 / PPTP_TIME_SCALE);
1004 	return(t);
1005 }
1006 
1007