kernel: Move us to using M_NOWAIT and M_WAITOK for mbuf functions.
[dragonfly.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 #include <sys/thread2.h>
65
66 #include <netinet/in.h>
67 #include <netinet/in_systm.h>
68 #include <netinet/ip.h>
69
70 #include <netgraph/ng_message.h>
71 #include <netgraph/netgraph.h>
72 #include <netgraph/ng_parse.h>
73 #include "ng_pptpgre.h"
74
75 /* GRE packet format, as used by PPTP */
76 struct greheader {
77 #if BYTE_ORDER == LITTLE_ENDIAN
78         u_char          recursion:3;            /* recursion control */
79         u_char          ssr:1;                  /* strict source route */
80         u_char          hasSeq:1;               /* sequence number present */
81         u_char          hasKey:1;               /* key present */
82         u_char          hasRoute:1;             /* routing present */
83         u_char          hasSum:1;               /* checksum present */
84         u_char          vers:3;                 /* version */
85         u_char          flags:4;                /* flags */
86         u_char          hasAck:1;               /* acknowlege number present */
87 #elif BYTE_ORDER == BIG_ENDIAN
88         u_char          hasSum:1;               /* checksum present */
89         u_char          hasRoute:1;             /* routing present */
90         u_char          hasKey:1;               /* key present */
91         u_char          hasSeq:1;               /* sequence number present */
92         u_char          ssr:1;                  /* strict source route */
93         u_char          recursion:3;            /* recursion control */
94         u_char          hasAck:1;               /* acknowlege number present */
95         u_char          flags:4;                /* flags */
96         u_char          vers:3;                 /* version */
97 #else
98 #error BYTE_ORDER is not defined properly
99 #endif
100         u_int16_t       proto;                  /* protocol (ethertype) */
101         u_int16_t       length;                 /* payload length */
102         u_int16_t       cid;                    /* call id */
103         u_int32_t       data[0];                /* opt. seq, ack, then data */
104 };
105
106 /* The PPTP protocol ID used in the GRE 'proto' field */
107 #define PPTP_GRE_PROTO          0x880b
108
109 /* Bits that must be set a certain way in all PPTP/GRE packets */
110 #define PPTP_INIT_VALUE         ((0x2001 << 16) | PPTP_GRE_PROTO)
111 #define PPTP_INIT_MASK          0xef7fffff
112
113 /* Min and max packet length */
114 #define PPTP_MAX_PAYLOAD        (0xffff - sizeof(struct greheader) - 8)
115
116 /* All times are scaled by this (PPTP_TIME_SCALE time units = 1 sec.) */
117 #define PPTP_TIME_SCALE         1000                    /* milliseconds */
118 typedef u_int64_t               pptptime_t;
119
120 /* Acknowledgment timeout parameters and functions */
121 #define PPTP_XMIT_WIN           16                      /* max xmit window */
122 #define PPTP_MIN_RTT            (PPTP_TIME_SCALE / 10)  /* 100 milliseconds */
123 #define PPTP_MIN_TIMEOUT        (PPTP_TIME_SCALE / 83)  /* 12 milliseconds */
124 #define PPTP_MAX_TIMEOUT        (10 * PPTP_TIME_SCALE)  /* 10 seconds */
125
126 /* When we recieve a packet, we wait to see if there's an outgoing packet
127    we can piggy-back the ACK off of. These parameters determine the mimimum
128    and maxmimum length of time we're willing to wait in order to do that.
129    These have no effect unless "enableDelayedAck" is turned on. */
130 #define PPTP_MIN_ACK_DELAY      (PPTP_TIME_SCALE / 500) /* 2 milliseconds */
131 #define PPTP_MAX_ACK_DELAY      (PPTP_TIME_SCALE / 2)   /* 500 milliseconds */
132
133 /* See RFC 2637 section 4.4 */
134 #define PPTP_ACK_ALPHA(x)       ((x) >> 3)      /* alpha = 0.125 */
135 #define PPTP_ACK_BETA(x)        ((x) >> 2)      /* beta = 0.25 */
136 #define PPTP_ACK_CHI(x)         ((x) << 2)      /* chi = 4 */
137 #define PPTP_ACK_DELTA(x)       ((x) << 1)      /* delta = 2 */
138
139 #define PPTP_SEQ_DIFF(x,y)      ((int32_t)(x) - (int32_t)(y))
140
141 /* We keep packet retransmit and acknowlegement state in this struct */
142 struct ng_pptpgre_ackp {
143         int32_t                 ato;            /* adaptive time-out value */
144         int32_t                 rtt;            /* round trip time estimate */
145         int32_t                 dev;            /* deviation estimate */
146         u_int16_t               xmitWin;        /* size of xmit window */
147         struct callout          sackTimer;      /* send ack timer */
148         struct callout          rackTimer;      /* recv ack timer */
149         node_p                  *sackTimerPtr;  /* send ack timer pointer */
150         node_p                  *rackTimerPtr;  /* recv ack timer pointer */
151         u_int32_t               winAck;         /* seq when xmitWin will grow */
152         pptptime_t              timeSent[PPTP_XMIT_WIN];
153 #ifdef DEBUG_RAT
154         pptptime_t              timerStart;     /* when rackTimer started */
155         pptptime_t              timerLength;    /* rackTimer duration */
156 #endif
157 };
158
159 /* Node private data */
160 struct ng_pptpgre_private {
161         hook_p                  upper;          /* hook to upper layers */
162         hook_p                  lower;          /* hook to lower layers */
163         struct ng_pptpgre_conf  conf;           /* configuration info */
164         struct ng_pptpgre_ackp  ackp;           /* packet transmit ack state */
165         u_int32_t               recvSeq;        /* last seq # we rcv'd */
166         u_int32_t               xmitSeq;        /* last seq # we sent */
167         u_int32_t               recvAck;        /* last seq # peer ack'd */
168         u_int32_t               xmitAck;        /* last seq # we ack'd */
169         u_int                   timers;         /* number of pending timers */
170         struct timeval          startTime;      /* time node was created */
171         struct ng_pptpgre_stats stats;          /* node statistics */
172 };
173 typedef struct ng_pptpgre_private *priv_p;
174
175 /* Netgraph node methods */
176 static ng_constructor_t ng_pptpgre_constructor;
177 static ng_rcvmsg_t      ng_pptpgre_rcvmsg;
178 static ng_shutdown_t    ng_pptpgre_rmnode;
179 static ng_newhook_t     ng_pptpgre_newhook;
180 static ng_rcvdata_t     ng_pptpgre_rcvdata;
181 static ng_disconnect_t  ng_pptpgre_disconnect;
182
183 /* Helper functions */
184 static int      ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta);
185 static int      ng_pptpgre_recv(node_p node, struct mbuf *m, meta_p meta);
186 static void     ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout);
187 static void     ng_pptpgre_stop_send_ack_timer(node_p node);
188 static void     ng_pptpgre_start_recv_ack_timer(node_p node);
189 static void     ng_pptpgre_stop_recv_ack_timer(node_p node);
190 static void     ng_pptpgre_recv_ack_timeout(void *arg);
191 static void     ng_pptpgre_send_ack_timeout(void *arg);
192 static void     ng_pptpgre_reset(node_p node);
193 static pptptime_t ng_pptpgre_time(node_p node);
194
195 /* Parse type for struct ng_pptpgre_conf */
196 static const struct ng_parse_struct_field ng_pptpgre_conf_type_fields[]
197         = NG_PPTPGRE_CONF_TYPE_INFO;
198 static const struct ng_parse_type ng_pptpgre_conf_type = {
199         &ng_parse_struct_type,
200         &ng_pptpgre_conf_type_fields,
201 };
202
203 /* Parse type for struct ng_pptpgre_stats */
204 static const struct ng_parse_struct_field ng_pptpgre_stats_type_fields[]
205         = NG_PPTPGRE_STATS_TYPE_INFO;
206 static const struct ng_parse_type ng_pptp_stats_type = {
207         &ng_parse_struct_type,
208         &ng_pptpgre_stats_type_fields
209 };
210
211 /* List of commands and how to convert arguments to/from ASCII */
212 static const struct ng_cmdlist ng_pptpgre_cmdlist[] = {
213         {
214           NGM_PPTPGRE_COOKIE,
215           NGM_PPTPGRE_SET_CONFIG,
216           "setconfig",
217           &ng_pptpgre_conf_type,
218           NULL
219         },
220         {
221           NGM_PPTPGRE_COOKIE,
222           NGM_PPTPGRE_GET_CONFIG,
223           "getconfig",
224           NULL,
225           &ng_pptpgre_conf_type
226         },
227         {
228           NGM_PPTPGRE_COOKIE,
229           NGM_PPTPGRE_GET_STATS,
230           "getstats",
231           NULL,
232           &ng_pptp_stats_type
233         },
234         {
235           NGM_PPTPGRE_COOKIE,
236           NGM_PPTPGRE_CLR_STATS,
237           "clrstats",
238           NULL,
239           NULL
240         },
241         {
242           NGM_PPTPGRE_COOKIE,
243           NGM_PPTPGRE_GETCLR_STATS,
244           "getclrstats",
245           NULL,
246           &ng_pptp_stats_type
247         },
248         { 0 }
249 };
250
251 /* Node type descriptor */
252 static struct ng_type ng_pptpgre_typestruct = {
253         NG_VERSION,
254         NG_PPTPGRE_NODE_TYPE,
255         NULL,
256         ng_pptpgre_constructor,
257         ng_pptpgre_rcvmsg,
258         ng_pptpgre_rmnode,
259         ng_pptpgre_newhook,
260         NULL,
261         NULL,
262         ng_pptpgre_rcvdata,
263         ng_pptpgre_rcvdata,
264         ng_pptpgre_disconnect,
265         ng_pptpgre_cmdlist
266 };
267 NETGRAPH_INIT(pptpgre, &ng_pptpgre_typestruct);
268
269 #define ERROUT(x)       do { error = (x); goto done; } while (0)
270
271 /************************************************************************
272                         NETGRAPH NODE STUFF
273  ************************************************************************/
274
275 /*
276  * Node type constructor
277  */
278 static int
279 ng_pptpgre_constructor(node_p *nodep)
280 {
281         priv_p priv;
282         int error;
283
284         /* Allocate private structure */
285         priv = kmalloc(sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
286         if (priv == NULL)
287                 return (ENOMEM);
288
289         /* Call generic node constructor */
290         if ((error = ng_make_node_common(&ng_pptpgre_typestruct, nodep))) {
291                 kfree(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                 kfree(resp, M_NETGRAPH);
391
392 done:
393         kfree(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", __func__);
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                 kfree(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", __func__);
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_NOWAIT, 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", __func__));
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         a->rackTimerPtr = kmalloc(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                 kfree(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         const node_p node = *((node_p *)arg);
803         const priv_p priv = node->private;
804         struct ng_pptpgre_ackp *const a = &priv->ackp;
805
806         crit_enter();
807         /* This complicated stuff is needed to avoid race conditions */
808         kfree(arg, M_NETGRAPH);
809         KASSERT(node->refs > 0, ("%s: no refs", __func__));
810         KASSERT(priv != NULL, ("%s: priv=NULL", __func__));
811         priv->timers--;
812         if ((node->flags & NG_INVALID) != 0) {  /* shutdown race condition */
813                 if (priv->timers == 0) {
814                         kfree(priv, M_NETGRAPH);
815                         node->private = NULL;
816                 }
817                 ng_unref(node);
818                 crit_exit();
819                 return;
820         }
821         if (arg != a->rackTimerPtr) {   /* timer stopped race condition */
822                 ng_unref(node);
823                 crit_exit();
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         crit_exit();
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", __func__));
865         a->sackTimerPtr = kmalloc(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                 kfree(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         const node_p node = *((node_p *)arg);
907         const priv_p priv = node->private;
908         struct ng_pptpgre_ackp *const a = &priv->ackp;
909
910         crit_enter();
911         /* This complicated stuff is needed to avoid race conditions */
912         kfree(arg, M_NETGRAPH);
913         KASSERT(node->refs > 0, ("%s: no refs", __func__));
914         KASSERT(priv != NULL, ("%s: priv=NULL", __func__));
915         priv->timers--;
916         if ((node->flags & NG_INVALID) != 0) {  /* shutdown race condition */
917                 if (priv->timers == 0) {
918                         kfree(priv, M_NETGRAPH);
919                         node->private = NULL;
920                 }
921                 ng_unref(node);
922                 crit_exit();
923                 return;
924         }
925         if (a->sackTimerPtr != arg) {   /* timer stopped race condition */
926                 ng_unref(node);
927                 crit_exit();
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         crit_exit();
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