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