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