6 * Copyright (c) 1996-1999 Whistle Communications, Inc.
9 * Subject to the following obligations and disclaimer of warranty, use and
10 * redistribution of this software, in source or object code forms, with or
11 * without modifications are expressly permitted by Whistle Communications;
12 * provided, however, that:
13 * 1. Any and all reproductions of the source or object code must include the
14 * copyright notice above and the following disclaimer of warranties; and
15 * 2. No rights are granted, in any manner or form, to use Whistle
16 * Communications, Inc. trademarks, including the mark "WHISTLE
17 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
18 * such appears in the above copyright notice or in the software.
20 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
21 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
22 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
23 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
25 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
26 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
27 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
28 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
29 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
30 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
38 * Author: Archie Cobbs <archie@freebsd.org>
41 * $Whistle: ng_pptpgre.c,v 1.7 1999/12/08 00:10:06 archie Exp $
45 * PPTP/GRE netgraph node type.
47 * This node type does the GRE encapsulation as specified for the PPTP
48 * protocol (RFC 2637, section 4). This includes sequencing and
49 * retransmission of frames, but not the actual packet delivery nor
50 * any of the TCP control stream protocol.
52 * The "upper" hook of this node is suitable for attaching to a "ppp"
53 * node link hook. The "lower" hook of this node is suitable for attaching
54 * to a "ksocket" node on hook "inet/raw/gre".
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/kernel.h>
62 #include <sys/malloc.h>
64 #include <sys/mutex.h>
65 #include <sys/errno.h>
67 #include <netinet/in.h>
68 #include <netinet/in_systm.h>
69 #include <netinet/ip.h>
71 #include <netgraph/ng_message.h>
72 #include <netgraph/netgraph.h>
73 #include <netgraph/ng_parse.h>
74 #include <netgraph/ng_pptpgre.h>
76 /* GRE packet format, as used by PPTP */
78 #if BYTE_ORDER == LITTLE_ENDIAN
79 u_char recursion:3; /* recursion control */
80 u_char ssr:1; /* strict source route */
81 u_char hasSeq:1; /* sequence number present */
82 u_char hasKey:1; /* key present */
83 u_char hasRoute:1; /* routing present */
84 u_char hasSum:1; /* checksum present */
85 u_char vers:3; /* version */
86 u_char flags:4; /* flags */
87 u_char hasAck:1; /* acknowlege number present */
88 #elif BYTE_ORDER == BIG_ENDIAN
89 u_char hasSum:1; /* checksum present */
90 u_char hasRoute:1; /* routing present */
91 u_char hasKey:1; /* key present */
92 u_char hasSeq:1; /* sequence number present */
93 u_char ssr:1; /* strict source route */
94 u_char recursion:3; /* recursion control */
95 u_char hasAck:1; /* acknowlege number present */
96 u_char flags:4; /* flags */
97 u_char vers:3; /* version */
99 #error BYTE_ORDER is not defined properly
101 u_int16_t proto; /* protocol (ethertype) */
102 u_int16_t length; /* payload length */
103 u_int16_t cid; /* call id */
104 u_int32_t data[0]; /* opt. seq, ack, then data */
107 /* The PPTP protocol ID used in the GRE 'proto' field */
108 #define PPTP_GRE_PROTO 0x880b
110 /* Bits that must be set a certain way in all PPTP/GRE packets */
111 #define PPTP_INIT_VALUE ((0x2001 << 16) | PPTP_GRE_PROTO)
112 #define PPTP_INIT_MASK 0xef7fffff
114 /* Min and max packet length */
115 #define PPTP_MAX_PAYLOAD (0xffff - sizeof(struct greheader) - 8)
117 /* All times are scaled by this (PPTP_TIME_SCALE time units = 1 sec.) */
118 #define PPTP_TIME_SCALE 1000 /* milliseconds */
119 typedef u_int64_t pptptime_t;
121 /* Acknowledgment timeout parameters and functions */
122 #define PPTP_XMIT_WIN 16 /* max xmit window */
123 #define PPTP_MIN_RTT (PPTP_TIME_SCALE / 10) /* 100 milliseconds */
124 #define PPTP_MIN_TIMEOUT (PPTP_TIME_SCALE / 83) /* 12 milliseconds */
125 #define PPTP_MAX_TIMEOUT (3 * PPTP_TIME_SCALE) /* 3 seconds */
127 /* When we recieve a packet, we wait to see if there's an outgoing packet
128 we can piggy-back the ACK off of. These parameters determine the mimimum
129 and maxmimum length of time we're willing to wait in order to do that.
130 These have no effect unless "enableDelayedAck" is turned on. */
131 #define PPTP_MIN_ACK_DELAY (PPTP_TIME_SCALE / 500) /* 2 milliseconds */
132 #define PPTP_MAX_ACK_DELAY (PPTP_TIME_SCALE / 2) /* 500 milliseconds */
134 /* See RFC 2637 section 4.4 */
135 #define PPTP_ACK_ALPHA(x) ((x) >> 3) /* alpha = 0.125 */
136 #define PPTP_ACK_BETA(x) ((x) >> 2) /* beta = 0.25 */
137 #define PPTP_ACK_CHI(x) ((x) << 2) /* chi = 4 */
138 #define PPTP_ACK_DELTA(x) ((x) << 1) /* delta = 2 */
140 #define PPTP_SEQ_DIFF(x,y) ((int32_t)(x) - (int32_t)(y))
142 /* We keep packet retransmit and acknowlegement state in this struct */
143 struct ng_pptpgre_ackp {
144 int32_t ato; /* adaptive time-out value */
145 int32_t rtt; /* round trip time estimate */
146 int32_t dev; /* deviation estimate */
147 u_int16_t xmitWin; /* size of xmit window */
148 struct callout sackTimer; /* send ack timer */
149 struct callout rackTimer; /* recv ack timer */
150 u_int32_t winAck; /* seq when xmitWin will grow */
151 pptptime_t timeSent[PPTP_XMIT_WIN];
153 pptptime_t timerStart; /* when rackTimer started */
154 pptptime_t timerLength; /* rackTimer duration */
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 struct timeval startTime; /* time node was created */
169 struct ng_pptpgre_stats stats; /* node statistics */
170 struct mtx mtx; /* node mutex */
172 typedef struct ng_pptpgre_private *priv_p;
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_shutdown;
178 static ng_newhook_t ng_pptpgre_newhook;
179 static ng_rcvdata_t ng_pptpgre_rcvdata;
180 static ng_disconnect_t ng_pptpgre_disconnect;
182 /* Helper functions */
183 static int ng_pptpgre_xmit(node_p node, item_p item);
184 static int ng_pptpgre_recv(node_p node, item_p item);
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(node_p node, hook_p hook,
190 void *arg1, int arg2);
191 static void ng_pptpgre_send_ack_timeout(node_p node, hook_p hook,
192 void *arg1, int arg2);
193 static void ng_pptpgre_reset(node_p node);
194 static pptptime_t ng_pptpgre_time(node_p node);
196 /* Parse type for struct ng_pptpgre_conf */
197 static const struct ng_parse_struct_field ng_pptpgre_conf_type_fields[]
198 = NG_PPTPGRE_CONF_TYPE_INFO;
199 static const struct ng_parse_type ng_pptpgre_conf_type = {
200 &ng_parse_struct_type,
201 &ng_pptpgre_conf_type_fields,
204 /* Parse type for struct ng_pptpgre_stats */
205 static const struct ng_parse_struct_field ng_pptpgre_stats_type_fields[]
206 = NG_PPTPGRE_STATS_TYPE_INFO;
207 static const struct ng_parse_type ng_pptp_stats_type = {
208 &ng_parse_struct_type,
209 &ng_pptpgre_stats_type_fields
212 /* List of commands and how to convert arguments to/from ASCII */
213 static const struct ng_cmdlist ng_pptpgre_cmdlist[] = {
216 NGM_PPTPGRE_SET_CONFIG,
218 &ng_pptpgre_conf_type,
223 NGM_PPTPGRE_GET_CONFIG,
226 &ng_pptpgre_conf_type
230 NGM_PPTPGRE_GET_STATS,
237 NGM_PPTPGRE_CLR_STATS,
244 NGM_PPTPGRE_GETCLR_STATS,
252 /* Node type descriptor */
253 static struct ng_type ng_pptpgre_typestruct = {
254 .version = NG_ABI_VERSION,
255 .name = NG_PPTPGRE_NODE_TYPE,
256 .constructor = ng_pptpgre_constructor,
257 .rcvmsg = ng_pptpgre_rcvmsg,
258 .shutdown = ng_pptpgre_shutdown,
259 .newhook = ng_pptpgre_newhook,
260 .rcvdata = ng_pptpgre_rcvdata,
261 .disconnect = ng_pptpgre_disconnect,
262 .cmdlist = ng_pptpgre_cmdlist,
264 NETGRAPH_INIT(pptpgre, &ng_pptpgre_typestruct);
266 #define ERROUT(x) do { error = (x); goto done; } while (0)
268 /************************************************************************
270 ************************************************************************/
273 * Node type constructor
276 ng_pptpgre_constructor(node_p node)
280 /* Allocate private structure */
281 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
285 NG_NODE_SET_PRIVATE(node, priv);
287 /* Initialize state */
288 mtx_init(&priv->mtx, "ng_pptp", NULL, MTX_DEF);
289 ng_callout_init(&priv->ackp.sackTimer);
290 ng_callout_init(&priv->ackp.rackTimer);
297 * Give our OK for a hook to be added.
300 ng_pptpgre_newhook(node_p node, hook_p hook, const char *name)
302 const priv_p priv = NG_NODE_PRIVATE(node);
305 /* Check hook name */
306 if (strcmp(name, NG_PPTPGRE_HOOK_UPPER) == 0)
307 hookPtr = &priv->upper;
308 else if (strcmp(name, NG_PPTPGRE_HOOK_LOWER) == 0)
309 hookPtr = &priv->lower;
313 /* See if already connected */
314 if (*hookPtr != NULL)
323 * Receive a control message.
326 ng_pptpgre_rcvmsg(node_p node, item_p item, hook_p lasthook)
328 const priv_p priv = NG_NODE_PRIVATE(node);
329 struct ng_mesg *resp = NULL;
333 NGI_GET_MSG(item, msg);
334 switch (msg->header.typecookie) {
335 case NGM_PPTPGRE_COOKIE:
336 switch (msg->header.cmd) {
337 case NGM_PPTPGRE_SET_CONFIG:
339 struct ng_pptpgre_conf *const newConf =
340 (struct ng_pptpgre_conf *) msg->data;
342 /* Check for invalid or illegal config */
343 if (msg->header.arglen != sizeof(*newConf))
345 ng_pptpgre_reset(node); /* reset on configure */
346 priv->conf = *newConf;
349 case NGM_PPTPGRE_GET_CONFIG:
350 NG_MKRESPONSE(resp, msg, sizeof(priv->conf), M_NOWAIT);
353 bcopy(&priv->conf, resp->data, sizeof(priv->conf));
355 case NGM_PPTPGRE_GET_STATS:
356 case NGM_PPTPGRE_CLR_STATS:
357 case NGM_PPTPGRE_GETCLR_STATS:
359 if (msg->header.cmd != NGM_PPTPGRE_CLR_STATS) {
360 NG_MKRESPONSE(resp, msg,
361 sizeof(priv->stats), M_NOWAIT);
365 resp->data, sizeof(priv->stats));
367 if (msg->header.cmd != NGM_PPTPGRE_GET_STATS)
368 bzero(&priv->stats, sizeof(priv->stats));
381 NG_RESPOND_MSG(error, node, item, resp);
387 * Receive incoming data on a hook.
390 ng_pptpgre_rcvdata(hook_p hook, item_p item)
392 const node_p node = NG_HOOK_NODE(hook);
393 const priv_p priv = NG_NODE_PRIVATE(node);
396 /* If not configured, reject */
397 if (!priv->conf.enabled) {
402 mtx_lock(&priv->mtx);
404 /* Treat as xmit or recv data */
405 if (hook == priv->upper)
406 rval = ng_pptpgre_xmit(node, item);
407 else if (hook == priv->lower)
408 rval = ng_pptpgre_recv(node, item);
410 panic("%s: weird hook", __func__);
412 mtx_assert(&priv->mtx, MA_NOTOWNED);
421 ng_pptpgre_shutdown(node_p node)
423 const priv_p priv = NG_NODE_PRIVATE(node);
425 /* Reset node (stops timers) */
426 ng_pptpgre_reset(node);
428 mtx_destroy(&priv->mtx);
430 FREE(priv, M_NETGRAPH);
432 /* Decrement ref count */
441 ng_pptpgre_disconnect(hook_p hook)
443 const node_p node = NG_HOOK_NODE(hook);
444 const priv_p priv = NG_NODE_PRIVATE(node);
446 /* Zero out hook pointer */
447 if (hook == priv->upper)
449 else if (hook == priv->lower)
452 panic("%s: unknown hook", __func__);
454 /* Go away if no longer connected to anything */
455 if ((NG_NODE_NUMHOOKS(node) == 0)
456 && (NG_NODE_IS_VALID(node)))
457 ng_rmnode_self(node);
461 /*************************************************************************
462 TRANSMIT AND RECEIVE FUNCTIONS
463 *************************************************************************/
466 * Transmit an outgoing frame, or just an ack if m is NULL.
469 ng_pptpgre_xmit(node_p node, item_p item)
471 const priv_p priv = NG_NODE_PRIVATE(node);
472 struct ng_pptpgre_ackp *const a = &priv->ackp;
473 u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)];
474 struct greheader *const gre = (struct greheader *)buf;
478 mtx_assert(&priv->mtx, MA_OWNED);
485 /* Check if there's data */
488 /* Check if windowing is enabled */
489 if (priv->conf.enableWindowing) {
490 /* Is our transmit window full? */
491 if ((u_int32_t)PPTP_SEQ_DIFF(priv->xmitSeq,
492 priv->recvAck) >= a->xmitWin) {
493 priv->stats.xmitDrops++;
498 /* Sanity check frame length */
499 if (m != NULL && m->m_pkthdr.len > PPTP_MAX_PAYLOAD) {
500 priv->stats.xmitTooBig++;
504 priv->stats.xmitLoneAcks++;
507 /* Build GRE header */
508 ((u_int32_t *)gre)[0] = htonl(PPTP_INIT_VALUE);
509 gre->length = (m != NULL) ? htons((u_short)m->m_pkthdr.len) : 0;
510 gre->cid = htons(priv->conf.peerCid);
512 /* Include sequence number if packet contains any data */
515 if (priv->conf.enableWindowing) {
516 a->timeSent[priv->xmitSeq - priv->recvAck]
517 = ng_pptpgre_time(node);
520 gre->data[0] = htonl(priv->xmitSeq);
523 /* Include acknowledgement (and stop send ack timer) if needed */
524 if (priv->conf.enableAlwaysAck || priv->xmitAck != priv->recvSeq) {
526 gre->data[gre->hasSeq] = htonl(priv->recvSeq);
527 priv->xmitAck = priv->recvSeq;
528 ng_pptpgre_stop_send_ack_timer(node);
531 /* Prepend GRE header to outgoing frame */
532 grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
534 MGETHDR(m, M_DONTWAIT, MT_DATA);
536 priv->stats.memoryFailures++;
539 m->m_len = m->m_pkthdr.len = grelen;
540 m->m_pkthdr.rcvif = NULL;
542 M_PREPEND(m, grelen, M_DONTWAIT);
543 if (m == NULL || (m->m_len < grelen
544 && (m = m_pullup(m, grelen)) == NULL)) {
545 priv->stats.memoryFailures++;
549 bcopy(gre, mtod(m, u_char *), grelen);
552 priv->stats.xmitPackets++;
553 priv->stats.xmitOctets += m->m_pkthdr.len;
556 * XXX: we should reset timer only after an item has been sent
559 if (gre->hasSeq && priv->xmitSeq == priv->recvAck + 1)
560 ng_pptpgre_start_recv_ack_timer(node);
562 mtx_unlock(&priv->mtx);
566 NG_FWD_NEW_DATA(error, item, priv->lower, m);
568 NG_SEND_DATA_ONLY(error, priv->lower, m);
574 mtx_unlock(&priv->mtx);
582 * Handle an incoming packet. The packet includes the IP header.
585 ng_pptpgre_recv(node_p node, item_p item)
587 const priv_p priv = NG_NODE_PRIVATE(node);
588 int iphlen, grelen, extralen;
589 const struct greheader *gre;
594 mtx_assert(&priv->mtx, MA_OWNED);
598 priv->stats.recvPackets++;
599 priv->stats.recvOctets += m->m_pkthdr.len;
601 /* Sanity check packet length */
602 if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) {
603 priv->stats.recvRunts++;
607 /* Safely pull up the complete IP+GRE headers */
608 if (m->m_len < sizeof(*ip) + sizeof(*gre)
609 && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) {
610 priv->stats.memoryFailures++;
613 ip = mtod(m, const struct ip *);
614 iphlen = ip->ip_hl << 2;
615 if (m->m_len < iphlen + sizeof(*gre)) {
616 if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) {
617 priv->stats.memoryFailures++;
620 ip = mtod(m, const struct ip *);
622 gre = (const struct greheader *)((const u_char *)ip + iphlen);
623 grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
624 if (m->m_pkthdr.len < iphlen + grelen) {
625 priv->stats.recvRunts++;
628 if (m->m_len < iphlen + grelen) {
629 if ((m = m_pullup(m, iphlen + grelen)) == NULL) {
630 priv->stats.memoryFailures++;
633 ip = mtod(m, const struct ip *);
634 gre = (const struct greheader *)((const u_char *)ip + iphlen);
637 /* Sanity check packet length and GRE header bits */
638 extralen = m->m_pkthdr.len
639 - (iphlen + grelen + gre->hasSeq * (u_int16_t)ntohs(gre->length));
641 priv->stats.recvBadGRE++;
644 if ((ntohl(*((const u_int32_t *)gre)) & PPTP_INIT_MASK)
645 != PPTP_INIT_VALUE) {
646 priv->stats.recvBadGRE++;
649 if (ntohs(gre->cid) != priv->conf.cid) {
650 priv->stats.recvBadCID++;
654 /* Look for peer ack */
656 struct ng_pptpgre_ackp *const a = &priv->ackp;
657 const u_int32_t ack = ntohl(gre->data[gre->hasSeq]);
658 const int index = ack - priv->recvAck - 1;
662 /* Sanity check ack value */
663 if (PPTP_SEQ_DIFF(ack, priv->xmitSeq) > 0) {
664 priv->stats.recvBadAcks++;
665 goto badAck; /* we never sent it! */
667 if (PPTP_SEQ_DIFF(ack, priv->recvAck) <= 0)
668 goto badAck; /* ack already timed out */
671 /* Update adaptive timeout stuff */
672 if (priv->conf.enableWindowing) {
673 sample = ng_pptpgre_time(node) - a->timeSent[index];
674 diff = sample - a->rtt;
675 a->rtt += PPTP_ACK_ALPHA(diff);
678 a->dev += PPTP_ACK_BETA(diff - a->dev);
679 a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
680 if (a->ato > PPTP_MAX_TIMEOUT)
681 a->ato = PPTP_MAX_TIMEOUT;
682 if (a->ato < PPTP_MIN_TIMEOUT)
683 a->ato = PPTP_MIN_TIMEOUT;
685 /* Shift packet transmit times in our transmit window */
686 bcopy(a->timeSent + index + 1, a->timeSent,
688 * (PPTP_XMIT_WIN - (index + 1)));
690 /* If we sent an entire window, increase window size */
691 if (PPTP_SEQ_DIFF(ack, a->winAck) >= 0
692 && a->xmitWin < PPTP_XMIT_WIN) {
694 a->winAck = ack + a->xmitWin;
697 /* Stop/(re)start receive ACK timer as necessary */
698 ng_pptpgre_stop_recv_ack_timer(node);
699 if (priv->recvAck != priv->xmitSeq)
700 ng_pptpgre_start_recv_ack_timer(node);
705 /* See if frame contains any data */
707 struct ng_pptpgre_ackp *const a = &priv->ackp;
708 const u_int32_t seq = ntohl(gre->data[0]);
710 /* Sanity check sequence number */
711 if (PPTP_SEQ_DIFF(seq, priv->recvSeq) <= 0) {
712 if (seq == priv->recvSeq)
713 priv->stats.recvDuplicates++;
715 priv->stats.recvOutOfOrder++;
720 /* We need to acknowledge this packet; do it soon... */
721 if (!(callout_pending(&a->sackTimer))) {
724 /* Take 1/4 of the estimated round trip time */
725 maxWait = (a->rtt >> 2);
727 /* If delayed ACK is disabled, send it now */
728 if (!priv->conf.enableDelayedAck) { /* ack now */
729 ng_pptpgre_xmit(node, NULL);
730 mtx_lock(&priv->mtx);
731 } else { /* ack later */
732 if (maxWait < PPTP_MIN_ACK_DELAY)
733 maxWait = PPTP_MIN_ACK_DELAY;
734 if (maxWait > PPTP_MAX_ACK_DELAY)
735 maxWait = PPTP_MAX_ACK_DELAY;
736 ng_pptpgre_start_send_ack_timer(node, maxWait);
740 /* Trim mbuf down to internal payload */
741 m_adj(m, iphlen + grelen);
745 mtx_unlock(&priv->mtx);
746 /* Deliver frame to upper layers */
747 NG_FWD_NEW_DATA(error, item, priv->upper, m);
749 priv->stats.recvLoneAcks++;
750 mtx_unlock(&priv->mtx);
752 NG_FREE_M(m); /* no data to deliver */
758 mtx_unlock(&priv->mtx);
764 /*************************************************************************
765 TIMER RELATED FUNCTIONS
766 *************************************************************************/
769 * Start a timer for the peer's acknowledging our oldest unacknowledged
770 * sequence number. If we get an ack for this sequence number before
771 * the timer goes off, we cancel the timer. Resets currently running
772 * recv ack timer, if any.
775 ng_pptpgre_start_recv_ack_timer(node_p node)
777 const priv_p priv = NG_NODE_PRIVATE(node);
778 struct ng_pptpgre_ackp *const a = &priv->ackp;
781 if (!priv->conf.enableWindowing)
784 /* Compute how long until oldest unack'd packet times out,
785 and reset the timer to that time. */
786 remain = (a->timeSent[0] + a->ato) - ng_pptpgre_time(node);
790 a->timerLength = remain;
791 a->timerStart = ng_pptpgre_time(node);
794 /* Be conservative: timeout can happen up to 1 tick early */
795 ticks = (((remain * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE) + 1;
796 ng_callout(&a->rackTimer, node, NULL, ticks,
797 ng_pptpgre_recv_ack_timeout, NULL, 0);
801 * Stop receive ack timer.
804 ng_pptpgre_stop_recv_ack_timer(node_p node)
806 const priv_p priv = NG_NODE_PRIVATE(node);
807 struct ng_pptpgre_ackp *const a = &priv->ackp;
809 if (!priv->conf.enableWindowing)
812 ng_uncallout(&a->rackTimer, node);
816 * The peer has failed to acknowledge the oldest unacknowledged sequence
817 * number within the time allotted. Update our adaptive timeout parameters
818 * and reset/restart the recv ack timer.
821 ng_pptpgre_recv_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2)
823 const priv_p priv = NG_NODE_PRIVATE(node);
824 struct ng_pptpgre_ackp *const a = &priv->ackp;
826 mtx_lock(&priv->mtx);
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;
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);
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 */
849 mtx_unlock(&priv->mtx);
853 * Start the send ack timer. This assumes the timer is not
857 ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout)
859 const priv_p priv = NG_NODE_PRIVATE(node);
860 struct ng_pptpgre_ackp *const a = &priv->ackp;
863 /* Be conservative: timeout can happen up to 1 tick early */
864 ticks = (((ackTimeout * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE);
865 ng_callout(&a->sackTimer, node, NULL, ticks,
866 ng_pptpgre_send_ack_timeout, NULL, 0);
870 * Stop send ack timer.
873 ng_pptpgre_stop_send_ack_timer(node_p node)
875 const priv_p priv = NG_NODE_PRIVATE(node);
876 struct ng_pptpgre_ackp *const a = &priv->ackp;
878 ng_uncallout(&a->sackTimer, node);
882 * We've waited as long as we're willing to wait before sending an
883 * acknowledgement to the peer for received frames. We had hoped to
884 * be able to piggy back our acknowledgement on an outgoing data frame,
885 * but apparently there haven't been any since. So send the ack now.
888 ng_pptpgre_send_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2)
890 const priv_p priv = NG_NODE_PRIVATE(node);
892 mtx_lock(&priv->mtx);
893 /* Send a frame with an ack but no payload */
894 ng_pptpgre_xmit(node, NULL);
895 mtx_assert(&priv->mtx, MA_NOTOWNED);
898 /*************************************************************************
900 *************************************************************************/
906 ng_pptpgre_reset(node_p node)
908 const priv_p priv = NG_NODE_PRIVATE(node);
909 struct ng_pptpgre_ackp *const a = &priv->ackp;
911 mtx_lock(&priv->mtx);
913 /* Reset adaptive timeout state */
914 a->ato = PPTP_MAX_TIMEOUT;
915 a->rtt = priv->conf.peerPpd * PPTP_TIME_SCALE / 10; /* ppd in 10ths */
916 if (a->rtt < PPTP_MIN_RTT)
917 a->rtt = PPTP_MIN_RTT;
919 a->xmitWin = (priv->conf.recvWin + 1) / 2;
920 if (a->xmitWin < 2) /* often the first packet is lost */
921 a->xmitWin = 2; /* because the peer isn't ready */
922 if (a->xmitWin > PPTP_XMIT_WIN)
923 a->xmitWin = PPTP_XMIT_WIN;
924 a->winAck = a->xmitWin;
926 /* Reset sequence numbers */
932 /* Reset start time */
933 getmicrouptime(&priv->startTime);
936 bzero(&priv->stats, sizeof(priv->stats));
939 ng_pptpgre_stop_send_ack_timer(node);
940 ng_pptpgre_stop_recv_ack_timer(node);
942 mtx_unlock(&priv->mtx);
946 * Return the current time scaled & translated to our internally used format.
949 ng_pptpgre_time(node_p node)
951 const priv_p priv = NG_NODE_PRIVATE(node);
956 if (tv.tv_sec < priv->startTime.tv_sec
957 || (tv.tv_sec == priv->startTime.tv_sec
958 && tv.tv_usec < priv->startTime.tv_usec))
960 timevalsub(&tv, &priv->startTime);
961 t = (pptptime_t)tv.tv_sec * PPTP_TIME_SCALE;
962 t += (pptptime_t)tv.tv_usec / (1000000 / PPTP_TIME_SCALE);