xref: /freebsd/sys/netgraph/ng_pptpgre.c (revision 2357939bc239bd5334a169b62313806178dd8f30)
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	(1 * PPTP_TIME_SCALE)	/* 1 second */
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 		/* Check if windowing is enabled */
481 		if (priv->conf.enableWindowing) {
482 			/* Is our transmit window full? */
483 			if ((u_int32_t)PPTP_SEQ_DIFF(priv->xmitSeq,
484 			    priv->recvAck) >= a->xmitWin) {
485 				priv->stats.xmitDrops++;
486 				NG_FREE_M(m);
487 				NG_FREE_ITEM(item);
488 				return (ENOBUFS);
489 			}
490 		}
491 
492 		/* Sanity check frame length */
493 		if (m != NULL && m->m_pkthdr.len > PPTP_MAX_PAYLOAD) {
494 			priv->stats.xmitTooBig++;
495 			NG_FREE_M(m);
496 			NG_FREE_ITEM(item);
497 			return (EMSGSIZE);
498 		}
499 	} else {
500 		priv->stats.xmitLoneAcks++;
501 	}
502 
503 	/* Build GRE header */
504 	((u_int32_t *)gre)[0] = htonl(PPTP_INIT_VALUE);
505 	gre->length = (m != NULL) ? htons((u_short)m->m_pkthdr.len) : 0;
506 	gre->cid = htons(priv->conf.peerCid);
507 
508 	/* Include sequence number if packet contains any data */
509 	if (m != NULL) {
510 		gre->hasSeq = 1;
511 		if (priv->conf.enableWindowing) {
512 			a->timeSent[priv->xmitSeq - priv->recvAck]
513 			    = ng_pptpgre_time(node);
514 		}
515 		priv->xmitSeq++;
516 		gre->data[0] = htonl(priv->xmitSeq);
517 	}
518 
519 	/* Include acknowledgement (and stop send ack timer) if needed */
520 	if (priv->conf.enableAlwaysAck || priv->xmitAck != priv->recvSeq) {
521 		gre->hasAck = 1;
522 		gre->data[gre->hasSeq] = htonl(priv->recvSeq);
523 		priv->xmitAck = priv->recvSeq;
524 		ng_pptpgre_stop_send_ack_timer(node);
525 	}
526 
527 	/* Prepend GRE header to outgoing frame */
528 	grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
529 	if (m == NULL) {
530 		MGETHDR(m, M_DONTWAIT, MT_DATA);
531 		if (m == NULL) {
532 			priv->stats.memoryFailures++;
533 			if (item)
534 				NG_FREE_ITEM(item);
535 			return (ENOBUFS);
536 		}
537 		m->m_len = m->m_pkthdr.len = grelen;
538 		m->m_pkthdr.rcvif = NULL;
539 	} else {
540 		M_PREPEND(m, grelen, M_DONTWAIT);
541 		if (m == NULL || (m->m_len < grelen
542 		    && (m = m_pullup(m, grelen)) == NULL)) {
543 			priv->stats.memoryFailures++;
544 			if (item)
545 				NG_FREE_ITEM(item);
546 			return (ENOBUFS);
547 		}
548 	}
549 	bcopy(gre, mtod(m, u_char *), grelen);
550 
551 	/* Update stats */
552 	priv->stats.xmitPackets++;
553 	priv->stats.xmitOctets += m->m_pkthdr.len;
554 
555 	/* Deliver packet */
556 	if (item) {
557 		NG_FWD_NEW_DATA(error, item, priv->lower, m);
558 	} else {
559 		NG_SEND_DATA_ONLY(error, priv->lower, m);
560 	}
561 
562 
563 	/* Start receive ACK timer if data was sent and not already running */
564 	if (error == 0 && gre->hasSeq && priv->xmitSeq == priv->recvAck + 1)
565 		ng_pptpgre_start_recv_ack_timer(node);
566 	return (error);
567 }
568 
569 /*
570  * Handle an incoming packet.  The packet includes the IP header.
571  */
572 static int
573 ng_pptpgre_recv(node_p node, item_p item)
574 {
575 	const priv_p priv = NG_NODE_PRIVATE(node);
576 	int iphlen, grelen, extralen;
577 	const struct greheader *gre;
578 	const struct ip *ip;
579 	int error = 0;
580 	struct mbuf *m;
581 
582 	NGI_GET_M(item, m);
583 	/* Update stats */
584 	priv->stats.recvPackets++;
585 	priv->stats.recvOctets += m->m_pkthdr.len;
586 
587 	/* Sanity check packet length */
588 	if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) {
589 		priv->stats.recvRunts++;
590 bad:
591 		NG_FREE_M(m);
592 		NG_FREE_ITEM(item);
593 		return (EINVAL);
594 	}
595 
596 	/* Safely pull up the complete IP+GRE headers */
597 	if (m->m_len < sizeof(*ip) + sizeof(*gre)
598 	    && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) {
599 		priv->stats.memoryFailures++;
600 		NG_FREE_ITEM(item);
601 		return (ENOBUFS);
602 	}
603 	ip = mtod(m, const struct ip *);
604 	iphlen = ip->ip_hl << 2;
605 	if (m->m_len < iphlen + sizeof(*gre)) {
606 		if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) {
607 			priv->stats.memoryFailures++;
608 			NG_FREE_ITEM(item);
609 			return (ENOBUFS);
610 		}
611 		ip = mtod(m, const struct ip *);
612 	}
613 	gre = (const struct greheader *)((const u_char *)ip + iphlen);
614 	grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
615 	if (m->m_pkthdr.len < iphlen + grelen) {
616 		priv->stats.recvRunts++;
617 		goto bad;
618 	}
619 	if (m->m_len < iphlen + grelen) {
620 		if ((m = m_pullup(m, iphlen + grelen)) == NULL) {
621 			priv->stats.memoryFailures++;
622 			NG_FREE_ITEM(item);
623 			return (ENOBUFS);
624 		}
625 		ip = mtod(m, const struct ip *);
626 		gre = (const struct greheader *)((const u_char *)ip + iphlen);
627 	}
628 
629 	/* Sanity check packet length and GRE header bits */
630 	extralen = m->m_pkthdr.len
631 	    - (iphlen + grelen + gre->hasSeq * (u_int16_t)ntohs(gre->length));
632 	if (extralen < 0) {
633 		priv->stats.recvBadGRE++;
634 		goto bad;
635 	}
636 	if ((ntohl(*((const u_int32_t *)gre)) & PPTP_INIT_MASK)
637 	    != PPTP_INIT_VALUE) {
638 		priv->stats.recvBadGRE++;
639 		goto bad;
640 	}
641 	if (ntohs(gre->cid) != priv->conf.cid) {
642 		priv->stats.recvBadCID++;
643 		goto bad;
644 	}
645 
646 	/* Look for peer ack */
647 	if (gre->hasAck) {
648 		struct ng_pptpgre_ackp *const a = &priv->ackp;
649 		const u_int32_t	ack = ntohl(gre->data[gre->hasSeq]);
650 		const int index = ack - priv->recvAck - 1;
651 		long sample;
652 		long diff;
653 
654 		/* Sanity check ack value */
655 		if (PPTP_SEQ_DIFF(ack, priv->xmitSeq) > 0) {
656 			priv->stats.recvBadAcks++;
657 			goto badAck;		/* we never sent it! */
658 		}
659 		if (PPTP_SEQ_DIFF(ack, priv->recvAck) <= 0)
660 			goto badAck;		/* ack already timed out */
661 		priv->recvAck = ack;
662 
663 		/* Update adaptive timeout stuff */
664 		if (priv->conf.enableWindowing) {
665 			sample = ng_pptpgre_time(node) - a->timeSent[index];
666 			diff = sample - a->rtt;
667 			a->rtt += PPTP_ACK_ALPHA(diff);
668 			if (diff < 0)
669 				diff = -diff;
670 			a->dev += PPTP_ACK_BETA(diff - a->dev);
671 			a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
672 			if (a->ato > PPTP_MAX_TIMEOUT)
673 				a->ato = PPTP_MAX_TIMEOUT;
674 			if (a->ato < PPTP_MIN_TIMEOUT)
675 				a->ato = PPTP_MIN_TIMEOUT;
676 
677 			/* Shift packet transmit times in our transmit window */
678 			bcopy(a->timeSent + index + 1, a->timeSent,
679 			    sizeof(*a->timeSent)
680 			      * (PPTP_XMIT_WIN - (index + 1)));
681 
682 			/* If we sent an entire window, increase window size */
683 			if (PPTP_SEQ_DIFF(ack, a->winAck) >= 0
684 			    && a->xmitWin < PPTP_XMIT_WIN) {
685 				a->xmitWin++;
686 				a->winAck = ack + a->xmitWin;
687 			}
688 
689 			/* Stop/(re)start receive ACK timer as necessary */
690 			ng_pptpgre_stop_recv_ack_timer(node);
691 			if (priv->recvAck != priv->xmitSeq)
692 				ng_pptpgre_start_recv_ack_timer(node);
693 		}
694 	}
695 badAck:
696 
697 	/* See if frame contains any data */
698 	if (gre->hasSeq) {
699 		struct ng_pptpgre_ackp *const a = &priv->ackp;
700 		const u_int32_t seq = ntohl(gre->data[0]);
701 
702 		/* Sanity check sequence number */
703 		if (PPTP_SEQ_DIFF(seq, priv->recvSeq) <= 0) {
704 			if (seq == priv->recvSeq)
705 				priv->stats.recvDuplicates++;
706 			else
707 				priv->stats.recvOutOfOrder++;
708 			goto bad;		/* out-of-order or dup */
709 		}
710 		priv->recvSeq = seq;
711 
712 		/* We need to acknowledge this packet; do it soon... */
713 		if (a->sackTimerPtr == NULL) {
714 			int maxWait;
715 
716 			/* Take 1/4 of the estimated round trip time */
717 			maxWait = (a->rtt >> 2);
718 
719 			/* If delayed ACK is disabled, send it now */
720 			if (!priv->conf.enableDelayedAck)	/* ack now */
721 				ng_pptpgre_xmit(node, NULL);
722 			else {					/* ack later */
723 				if (maxWait < PPTP_MIN_ACK_DELAY)
724 					maxWait = PPTP_MIN_ACK_DELAY;
725 				if (maxWait > PPTP_MAX_ACK_DELAY)
726 					maxWait = PPTP_MAX_ACK_DELAY;
727 				ng_pptpgre_start_send_ack_timer(node, maxWait);
728 			}
729 		}
730 
731 		/* Trim mbuf down to internal payload */
732 		m_adj(m, iphlen + grelen);
733 		if (extralen > 0)
734 			m_adj(m, -extralen);
735 
736 		/* Deliver frame to upper layers */
737 		NG_FWD_NEW_DATA(error, item, priv->upper, m);
738 	} else {
739 		priv->stats.recvLoneAcks++;
740 		NG_FREE_ITEM(item);
741 		NG_FREE_M(m);		/* no data to deliver */
742 	}
743 	return (error);
744 }
745 
746 /*************************************************************************
747 		    TIMER RELATED FUNCTIONS
748 *************************************************************************/
749 
750 /*
751  * Start a timer for the peer's acknowledging our oldest unacknowledged
752  * sequence number.  If we get an ack for this sequence number before
753  * the timer goes off, we cancel the timer.  Resets currently running
754  * recv ack timer, if any.
755  */
756 static void
757 ng_pptpgre_start_recv_ack_timer(node_p node)
758 {
759 	const priv_p priv = NG_NODE_PRIVATE(node);
760 	struct ng_pptpgre_ackp *const a = &priv->ackp;
761 	int remain, ticks;
762 
763 	if (!priv->conf.enableWindowing)
764 		return;
765 
766 	/* Compute how long until oldest unack'd packet times out,
767 	   and reset the timer to that time. */
768 	KASSERT(a->rackTimerPtr == NULL, ("%s: rackTimer", __func__));
769 	remain = (a->timeSent[0] + a->ato) - ng_pptpgre_time(node);
770 	if (remain < 0)
771 		remain = 0;
772 #ifdef DEBUG_RAT
773 	a->timerLength = remain;
774 	a->timerStart = ng_pptpgre_time(node);
775 #endif
776 
777 	/* Start new timer */
778 	MALLOC(a->rackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT);
779 	if (a->rackTimerPtr == NULL) {
780 		priv->stats.memoryFailures++;
781 		return;			/* XXX potential hang here */
782 	}
783 	*a->rackTimerPtr = node;	/* ensures the correct timeout event */
784 	NG_NODE_REF(node);
785 	priv->timers++;
786 
787 	/* Be conservative: timeout can happen up to 1 tick early */
788 	ticks = (((remain * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE) + 1;
789 	callout_reset(&a->rackTimer, ticks,
790 	    ng_pptpgre_recv_ack_timeout, a->rackTimerPtr);
791 }
792 
793 /*
794  * Stop receive ack timer.
795  */
796 static void
797 ng_pptpgre_stop_recv_ack_timer(node_p node)
798 {
799 	const priv_p priv = NG_NODE_PRIVATE(node);
800 	struct ng_pptpgre_ackp *const a = &priv->ackp;
801 
802 	if (!priv->conf.enableWindowing)
803 		return;
804 
805 	if (callout_stop(&a->rackTimer)) {
806 		FREE(a->rackTimerPtr, M_NETGRAPH);
807 		priv->timers--;
808 		NG_NODE_UNREF(node);
809 	}
810 	a->rackTimerPtr = NULL;
811 }
812 
813 /*
814  * The peer has failed to acknowledge the oldest unacknowledged sequence
815  * number within the time allotted.  Update our adaptive timeout parameters
816  * and reset/restart the recv ack timer.
817  */
818 static void
819 ng_pptpgre_recv_ack_timeout(void *arg)
820 {
821 	int s = splnet();
822 	const node_p node = *((node_p *)arg);
823 	const priv_p priv = NG_NODE_PRIVATE(node);
824 	struct ng_pptpgre_ackp *const a = &priv->ackp;
825 
826 	/* This complicated stuff is needed to avoid race conditions */
827 	FREE(arg, M_NETGRAPH);
828 	KASSERT(node->nd_refs > 0, ("%s: no nd_refs", __func__));
829 	KASSERT(priv != NULL, ("%s: priv=NULL", __func__));
830 	priv->timers--;
831 	if (NG_NODE_NOT_VALID(node)) {	/* shutdown race condition */
832 		if (priv->timers == 0) {
833 			FREE(priv, M_NETGRAPH);
834 			NG_NODE_SET_PRIVATE(node, NULL);
835 		}
836 		NG_NODE_UNREF(node);
837 		splx(s);
838 		return;
839 	}
840 	if (arg != a->rackTimerPtr) {	/* timer stopped race condition */
841 		NG_NODE_UNREF(node);
842 		splx(s);
843 		return;
844 	}
845 	a->rackTimerPtr = NULL;
846 
847 	/* Update adaptive timeout stuff */
848 	priv->stats.recvAckTimeouts++;
849 	a->rtt = PPTP_ACK_DELTA(a->rtt);
850 	a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
851 	if (a->ato > PPTP_MAX_TIMEOUT)
852 		a->ato = PPTP_MAX_TIMEOUT;
853 	if (a->ato < PPTP_MIN_TIMEOUT)
854 		a->ato = PPTP_MIN_TIMEOUT;
855 
856 #ifdef DEBUG_RAT
857     log(LOG_DEBUG,
858 	"RAT now=%d seq=0x%x sent=%d tstart=%d tlen=%d ato=%d\n",
859 	(int)ng_pptpgre_time(node), priv->recvAck + 1,
860 	(int)a->timeSent[0], (int)a->timerStart, (int)a->timerLength, a->ato);
861 #endif
862 
863 	/* Reset ack and sliding window */
864 	priv->recvAck = priv->xmitSeq;		/* pretend we got the ack */
865 	a->xmitWin = (a->xmitWin + 1) / 2;	/* shrink transmit window */
866 	a->winAck = priv->recvAck + a->xmitWin;	/* reset win expand time */
867 	NG_NODE_UNREF(node);
868 	splx(s);
869 }
870 
871 /*
872  * Start the send ack timer. This assumes the timer is not
873  * already running.
874  */
875 static void
876 ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout)
877 {
878 	const priv_p priv = NG_NODE_PRIVATE(node);
879 	struct ng_pptpgre_ackp *const a = &priv->ackp;
880 	int ticks;
881 
882 	/* Start new timer */
883 	KASSERT(a->sackTimerPtr == NULL, ("%s: sackTimer", __func__));
884 	MALLOC(a->sackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT);
885 	if (a->sackTimerPtr == NULL) {
886 		priv->stats.memoryFailures++;
887 		return;			/* XXX potential hang here */
888 	}
889 	*a->sackTimerPtr = node;	/* ensures the correct timeout event */
890 	NG_NODE_REF(node);
891 	priv->timers++;
892 
893 	/* Be conservative: timeout can happen up to 1 tick early */
894 	ticks = (((ackTimeout * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE);
895 	callout_reset(&a->sackTimer, ticks,
896 	    ng_pptpgre_send_ack_timeout, a->sackTimerPtr);
897 }
898 
899 /*
900  * Stop send ack timer.
901  */
902 static void
903 ng_pptpgre_stop_send_ack_timer(node_p node)
904 {
905 	const priv_p priv = NG_NODE_PRIVATE(node);
906 	struct ng_pptpgre_ackp *const a = &priv->ackp;
907 
908 	if (callout_stop(&a->sackTimer)) {
909 		FREE(a->sackTimerPtr, M_NETGRAPH);
910 		priv->timers--;
911 		NG_NODE_UNREF(node);
912 	}
913 	a->sackTimerPtr = NULL;
914 }
915 
916 /*
917  * We've waited as long as we're willing to wait before sending an
918  * acknowledgement to the peer for received frames. We had hoped to
919  * be able to piggy back our acknowledgement on an outgoing data frame,
920  * but apparently there haven't been any since. So send the ack now.
921  */
922 static void
923 ng_pptpgre_send_ack_timeout(void *arg)
924 {
925 	int s = splnet();
926 	const node_p node = *((node_p *)arg);
927 	const priv_p priv = NG_NODE_PRIVATE(node);
928 	struct ng_pptpgre_ackp *const a = &priv->ackp;
929 
930 	/* This complicated stuff is needed to avoid race conditions */
931 	FREE(arg, M_NETGRAPH);
932 	KASSERT(node->nd_refs > 0, ("%s: no nd_refs", __func__));
933 	KASSERT(priv != NULL, ("%s: priv=NULL", __func__));
934 	priv->timers--;
935 	if (NG_NODE_NOT_VALID(node)) {	/* shutdown race condition */
936 		if (priv->timers == 0) {
937 			FREE(priv, M_NETGRAPH);
938 			NG_NODE_SET_PRIVATE(node, NULL);
939 		}
940 		NG_NODE_UNREF(node);
941 		splx(s);
942 		return;
943 	}
944 	if (a->sackTimerPtr != arg) {	/* timer stopped race condition */
945 		NG_NODE_UNREF(node);
946 		splx(s);
947 		return;
948 	}
949 	a->sackTimerPtr = NULL;
950 
951 	/* Send a frame with an ack but no payload */
952   	ng_pptpgre_xmit(node, NULL);
953 	NG_NODE_UNREF(node);
954 	splx(s);
955 }
956 
957 /*************************************************************************
958 		    MISC FUNCTIONS
959 *************************************************************************/
960 
961 /*
962  * Reset state
963  */
964 static void
965 ng_pptpgre_reset(node_p node)
966 {
967 	const priv_p priv = NG_NODE_PRIVATE(node);
968 	struct ng_pptpgre_ackp *const a = &priv->ackp;
969 
970 	/* Reset adaptive timeout state */
971 	a->ato = PPTP_MAX_TIMEOUT;
972 	a->rtt = priv->conf.peerPpd * PPTP_TIME_SCALE / 10;  /* ppd in 10ths */
973 	if (a->rtt < PPTP_MIN_RTT)
974 		a->rtt = PPTP_MIN_RTT;
975 	a->dev = 0;
976 	a->xmitWin = (priv->conf.recvWin + 1) / 2;
977 	if (a->xmitWin < 2)		/* often the first packet is lost */
978 		a->xmitWin = 2;		/*   because the peer isn't ready */
979 	if (a->xmitWin > PPTP_XMIT_WIN)
980 		a->xmitWin = PPTP_XMIT_WIN;
981 	a->winAck = a->xmitWin;
982 
983 	/* Reset sequence numbers */
984 	priv->recvSeq = ~0;
985 	priv->recvAck = ~0;
986 	priv->xmitSeq = ~0;
987 	priv->xmitAck = ~0;
988 
989 	/* Reset start time */
990 	getmicrouptime(&priv->startTime);
991 
992 	/* Reset stats */
993 	bzero(&priv->stats, sizeof(priv->stats));
994 
995 	/* Stop timers */
996 	ng_pptpgre_stop_send_ack_timer(node);
997 	ng_pptpgre_stop_recv_ack_timer(node);
998 }
999 
1000 /*
1001  * Return the current time scaled & translated to our internally used format.
1002  */
1003 static pptptime_t
1004 ng_pptpgre_time(node_p node)
1005 {
1006 	const priv_p priv = NG_NODE_PRIVATE(node);
1007 	struct timeval tv;
1008 	pptptime_t t;
1009 
1010 	microuptime(&tv);
1011 	if (tv.tv_sec < priv->startTime.tv_sec
1012 	    || (tv.tv_sec == priv->startTime.tv_sec
1013 	      && tv.tv_usec < priv->startTime.tv_usec))
1014 		return (0);
1015 	timevalsub(&tv, &priv->startTime);
1016 	t = (pptptime_t)tv.tv_sec * PPTP_TIME_SCALE;
1017 	t += (pptptime_t)tv.tv_usec / (1000000 / PPTP_TIME_SCALE);
1018 	return(t);
1019 }
1020 
1021