xref: /freebsd/sys/netgraph/ng_pptpgre.c (revision ee2ea5ceafed78a5bd9810beb9e3ca927180c226)
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_info
195 	ng_pptpgre_conf_type_info = 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_info,
199 };
200 
201 /* Parse type for struct ng_pptpgre_stats */
202 static const struct ng_parse_struct_info
203 	ng_pptpgre_stats_type_info = 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_info
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 	struct greheader *gre;
573 	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, 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, struct ip *);
607 	}
608 	gre = (struct greheader *)((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, struct ip *);
621 		gre = (struct greheader *)((u_char *)ip + iphlen);
622 	}
623 
624 	/* Sanity check packet length and GRE header bits */
625 	extralen = m->m_pkthdr.len
626 	    - (iphlen + grelen + (u_int16_t)ntohs(gre->length));
627 	if (extralen < 0) {
628 		priv->stats.recvBadGRE++;
629 		goto bad;
630 	}
631 	if ((ntohl(*((u_int32_t *)gre)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE) {
632 		priv->stats.recvBadGRE++;
633 		goto bad;
634 	}
635 	if (ntohs(gre->cid) != priv->conf.cid) {
636 		priv->stats.recvBadCID++;
637 		goto bad;
638 	}
639 
640 	/* Look for peer ack */
641 	if (gre->hasAck) {
642 		struct ng_pptpgre_ackp *const a = &priv->ackp;
643 		const u_int32_t	ack = ntohl(gre->data[gre->hasSeq]);
644 		const int index = ack - priv->recvAck - 1;
645 		long sample;
646 		long diff;
647 
648 		/* Sanity check ack value */
649 		if (PPTP_SEQ_DIFF(ack, priv->xmitSeq) > 0) {
650 			priv->stats.recvBadAcks++;
651 			goto badAck;		/* we never sent it! */
652 		}
653 		if (PPTP_SEQ_DIFF(ack, priv->recvAck) <= 0)
654 			goto badAck;		/* ack already timed out */
655 		priv->recvAck = ack;
656 
657 		/* Update adaptive timeout stuff */
658 		sample = ng_pptpgre_time(node) - a->timeSent[index];
659 		diff = sample - a->rtt;
660 		a->rtt += PPTP_ACK_ALPHA(diff);
661 		if (diff < 0)
662 			diff = -diff;
663 		a->dev += PPTP_ACK_BETA(diff - a->dev);
664 		a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
665 		if (a->ato > PPTP_MAX_TIMEOUT)
666 			a->ato = PPTP_MAX_TIMEOUT;
667 		if (a->ato < PPTP_MIN_TIMEOUT)
668 			a->ato = PPTP_MIN_TIMEOUT;
669 
670 		/* Shift packet transmit times in our transmit window */
671 		ovbcopy(a->timeSent + index + 1, a->timeSent,
672 		    sizeof(*a->timeSent) * (PPTP_XMIT_WIN - (index + 1)));
673 
674 		/* If we sent an entire window, increase window size by one */
675 		if (PPTP_SEQ_DIFF(ack, a->winAck) >= 0
676 		    && a->xmitWin < PPTP_XMIT_WIN) {
677 			a->xmitWin++;
678 			a->winAck = ack + a->xmitWin;
679 		}
680 
681 		/* Stop/(re)start receive ACK timer as necessary */
682 		ng_pptpgre_stop_recv_ack_timer(node);
683 		if (priv->recvAck != priv->xmitSeq)
684 			ng_pptpgre_start_recv_ack_timer(node);
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->sackTimerPtr == NULL) {
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 	/* Compute how long until oldest unack'd packet times out,
755 	   and reset the timer to that time. */
756 	KASSERT(a->rackTimerPtr == NULL, ("%s: rackTimer", __func__));
757 	remain = (a->timeSent[0] + a->ato) - ng_pptpgre_time(node);
758 	if (remain < 0)
759 		remain = 0;
760 #ifdef DEBUG_RAT
761 	a->timerLength = remain;
762 	a->timerStart = ng_pptpgre_time(node);
763 #endif
764 
765 	/* Start new timer */
766 	MALLOC(a->rackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT);
767 	if (a->rackTimerPtr == NULL) {
768 		priv->stats.memoryFailures++;
769 		return;			/* XXX potential hang here */
770 	}
771 	*a->rackTimerPtr = node;	/* ensures the correct timeout event */
772 	NG_NODE_REF(node);
773 	priv->timers++;
774 
775 	/* Be conservative: timeout can happen up to 1 tick early */
776 	ticks = (((remain * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE) + 1;
777 	callout_reset(&a->rackTimer, ticks,
778 	    ng_pptpgre_recv_ack_timeout, a->rackTimerPtr);
779 }
780 
781 /*
782  * Stop receive ack timer.
783  */
784 static void
785 ng_pptpgre_stop_recv_ack_timer(node_p node)
786 {
787 	const priv_p priv = NG_NODE_PRIVATE(node);
788 	struct ng_pptpgre_ackp *const a = &priv->ackp;
789 
790 	if (callout_stop(&a->rackTimer)) {
791 		FREE(a->rackTimerPtr, M_NETGRAPH);
792 		priv->timers--;
793 		NG_NODE_UNREF(node);
794 	}
795 	a->rackTimerPtr = NULL;
796 }
797 
798 /*
799  * The peer has failed to acknowledge the oldest unacknowledged sequence
800  * number within the time allotted.  Update our adaptive timeout parameters
801  * and reset/restart the recv ack timer.
802  */
803 static void
804 ng_pptpgre_recv_ack_timeout(void *arg)
805 {
806 	int s = splnet();
807 	const node_p node = *((node_p *)arg);
808 	const priv_p priv = NG_NODE_PRIVATE(node);
809 	struct ng_pptpgre_ackp *const a = &priv->ackp;
810 
811 	/* This complicated stuff is needed to avoid race conditions */
812 	FREE(arg, M_NETGRAPH);
813 	KASSERT(node->nd_refs > 0, ("%s: no nd_refs", __func__));
814 	KASSERT(priv != NULL, ("%s: priv=NULL", __func__));
815 	priv->timers--;
816 	if (NG_NODE_NOT_VALID(node)) {	/* shutdown race condition */
817 		if (priv->timers == 0) {
818 			FREE(priv, M_NETGRAPH);
819 			NG_NODE_SET_PRIVATE(node, NULL);
820 		}
821 		NG_NODE_UNREF(node);
822 		splx(s);
823 		return;
824 	}
825 	if (arg != a->rackTimerPtr) {	/* timer stopped race condition */
826 		NG_NODE_UNREF(node);
827 		splx(s);
828 		return;
829 	}
830 	a->rackTimerPtr = NULL;
831 
832 	/* Update adaptive timeout stuff */
833 	priv->stats.recvAckTimeouts++;
834 	a->rtt = PPTP_ACK_DELTA(a->rtt);
835 	a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
836 	if (a->ato > PPTP_MAX_TIMEOUT)
837 		a->ato = PPTP_MAX_TIMEOUT;
838 	if (a->ato < PPTP_MIN_TIMEOUT)
839 		a->ato = PPTP_MIN_TIMEOUT;
840 
841 #ifdef DEBUG_RAT
842     log(LOG_DEBUG,
843 	"RAT now=%d seq=0x%x sent=%d tstart=%d tlen=%d ato=%d\n",
844 	(int)ng_pptpgre_time(node), priv->recvAck + 1,
845 	(int)a->timeSent[0], (int)a->timerStart, (int)a->timerLength, a->ato);
846 #endif
847 
848 	/* Reset ack and sliding window */
849 	priv->recvAck = priv->xmitSeq;		/* pretend we got the ack */
850 	a->xmitWin = (a->xmitWin + 1) / 2;	/* shrink transmit window */
851 	a->winAck = priv->recvAck + a->xmitWin;	/* reset win expand time */
852 	NG_NODE_UNREF(node);
853 	splx(s);
854 }
855 
856 /*
857  * Start the send ack timer. This assumes the timer is not
858  * already running.
859  */
860 static void
861 ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout)
862 {
863 	const priv_p priv = NG_NODE_PRIVATE(node);
864 	struct ng_pptpgre_ackp *const a = &priv->ackp;
865 	int ticks;
866 
867 	/* Start new timer */
868 	KASSERT(a->sackTimerPtr == NULL, ("%s: sackTimer", __func__));
869 	MALLOC(a->sackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT);
870 	if (a->sackTimerPtr == NULL) {
871 		priv->stats.memoryFailures++;
872 		return;			/* XXX potential hang here */
873 	}
874 	*a->sackTimerPtr = node;	/* ensures the correct timeout event */
875 	NG_NODE_REF(node);
876 	priv->timers++;
877 
878 	/* Be conservative: timeout can happen up to 1 tick early */
879 	ticks = (((ackTimeout * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE);
880 	callout_reset(&a->sackTimer, ticks,
881 	    ng_pptpgre_send_ack_timeout, a->sackTimerPtr);
882 }
883 
884 /*
885  * Stop send ack timer.
886  */
887 static void
888 ng_pptpgre_stop_send_ack_timer(node_p node)
889 {
890 	const priv_p priv = NG_NODE_PRIVATE(node);
891 	struct ng_pptpgre_ackp *const a = &priv->ackp;
892 
893 	if (callout_stop(&a->sackTimer)) {
894 		FREE(a->sackTimerPtr, M_NETGRAPH);
895 		priv->timers--;
896 		NG_NODE_UNREF(node);
897 	}
898 	a->sackTimerPtr = NULL;
899 }
900 
901 /*
902  * We've waited as long as we're willing to wait before sending an
903  * acknowledgement to the peer for received frames. We had hoped to
904  * be able to piggy back our acknowledgement on an outgoing data frame,
905  * but apparently there haven't been any since. So send the ack now.
906  */
907 static void
908 ng_pptpgre_send_ack_timeout(void *arg)
909 {
910 	int s = splnet();
911 	const node_p node = *((node_p *)arg);
912 	const priv_p priv = NG_NODE_PRIVATE(node);
913 	struct ng_pptpgre_ackp *const a = &priv->ackp;
914 
915 	/* This complicated stuff is needed to avoid race conditions */
916 	FREE(arg, M_NETGRAPH);
917 	KASSERT(node->nd_refs > 0, ("%s: no nd_refs", __func__));
918 	KASSERT(priv != NULL, ("%s: priv=NULL", __func__));
919 	priv->timers--;
920 	if (NG_NODE_NOT_VALID(node)) {	/* shutdown race condition */
921 		if (priv->timers == 0) {
922 			FREE(priv, M_NETGRAPH);
923 			NG_NODE_SET_PRIVATE(node, NULL);
924 		}
925 		NG_NODE_UNREF(node);
926 		splx(s);
927 		return;
928 	}
929 	if (a->sackTimerPtr != arg) {	/* timer stopped race condition */
930 		NG_NODE_UNREF(node);
931 		splx(s);
932 		return;
933 	}
934 	a->sackTimerPtr = NULL;
935 
936 	/* Send a frame with an ack but no payload */
937   	ng_pptpgre_xmit(node, NULL);
938 	NG_NODE_UNREF(node);
939 	splx(s);
940 }
941 
942 /*************************************************************************
943 		    MISC FUNCTIONS
944 *************************************************************************/
945 
946 /*
947  * Reset state
948  */
949 static void
950 ng_pptpgre_reset(node_p node)
951 {
952 	const priv_p priv = NG_NODE_PRIVATE(node);
953 	struct ng_pptpgre_ackp *const a = &priv->ackp;
954 
955 	/* Reset adaptive timeout state */
956 	a->ato = PPTP_MAX_TIMEOUT;
957 	a->rtt = priv->conf.peerPpd * PPTP_TIME_SCALE / 10;  /* ppd in 10ths */
958 	if (a->rtt < PPTP_MIN_RTT)
959 		a->rtt = PPTP_MIN_RTT;
960 	a->dev = 0;
961 	a->xmitWin = (priv->conf.recvWin + 1) / 2;
962 	if (a->xmitWin < 2)		/* often the first packet is lost */
963 		a->xmitWin = 2;		/*   because the peer isn't ready */
964 	if (a->xmitWin > PPTP_XMIT_WIN)
965 		a->xmitWin = PPTP_XMIT_WIN;
966 	a->winAck = a->xmitWin;
967 
968 	/* Reset sequence numbers */
969 	priv->recvSeq = ~0;
970 	priv->recvAck = ~0;
971 	priv->xmitSeq = ~0;
972 	priv->xmitAck = ~0;
973 
974 	/* Reset start time */
975 	getmicrouptime(&priv->startTime);
976 
977 	/* Reset stats */
978 	bzero(&priv->stats, sizeof(priv->stats));
979 
980 	/* Stop timers */
981 	ng_pptpgre_stop_send_ack_timer(node);
982 	ng_pptpgre_stop_recv_ack_timer(node);
983 }
984 
985 /*
986  * Return the current time scaled & translated to our internally used format.
987  */
988 static pptptime_t
989 ng_pptpgre_time(node_p node)
990 {
991 	const priv_p priv = NG_NODE_PRIVATE(node);
992 	struct timeval tv;
993 	pptptime_t t;
994 
995 	microuptime(&tv);
996 	if (tv.tv_sec < priv->startTime.tv_sec
997 	    || (tv.tv_sec == priv->startTime.tv_sec
998 	      && tv.tv_usec < priv->startTime.tv_usec))
999 		return (0);
1000 	timevalsub(&tv, &priv->startTime);
1001 	t = (pptptime_t)tv.tv_sec * PPTP_TIME_SCALE;
1002 	t += (pptptime_t)tv.tv_usec / (1000000 / PPTP_TIME_SCALE);
1003 	return(t);
1004 }
1005 
1006