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