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