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